Merge branch '3.1.x'
This commit is contained in:
commit
3798626a90
|
|
@ -20,8 +20,8 @@ Instructions on
|
|||
via Maven and other build systems are available via the project wiki.
|
||||
|
||||
## Documentation
|
||||
See the current [Javadoc](http://static.springsource.org/spring/docs/current/javadoc-api)
|
||||
and [Reference docs](http://static.springsource.org/spring/docs/current/spring-framework-reference).
|
||||
See the current [Javadoc](http://static.springsource.org/spring-framework/docs/current/api)
|
||||
and [Reference docs](http://static.springsource.org/spring-framework/docs/current/reference).
|
||||
|
||||
## Getting support
|
||||
Check out the [Spring forums](http://forum.springsource.org) and the
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ http://www.springsource.org
|
|||
Changes in version 3.1.1 (2012-02-06)
|
||||
-------------------------------------
|
||||
|
||||
* official support for Hibernate 4.0 GA
|
||||
* official support for Hibernate 4.0 GA (as released in the meantime)
|
||||
* JBossNativeJdbcExtractor is compatible with JBoss AS 7 as well
|
||||
* context:property-placeholder's "file-encoding" attribute value is being applied correctly
|
||||
* DataBinder correctly handles ParseException from Formatter for String->String case
|
||||
|
|
@ -19,8 +19,14 @@ Changes in version 3.1.1 (2012-02-06)
|
|||
* Hibernate 4 LocalSessionFactoryBean implements PersistenceExceptionTranslator interface as well
|
||||
* Hibernate 4 LocalSessionFactoryBean does not insist on a "dataSource" reference being set
|
||||
* added "entityInterceptor" property to Hibernate 4 LocalSessionFactoryBean
|
||||
* added "getConfiguration" accessor to Hibernate 4 LocalSessionFactoryBean
|
||||
* corrected fix for QuartzJobBean to work with Quartz 2.0/2.1
|
||||
|
||||
* JMS CachingConnectionFactory never caches consumers for temporary queues and topics
|
||||
* JMS SimpleMessageListenerContainer silently falls back to lazy registration of consumers
|
||||
* fix regresion in UriUtils
|
||||
* allow adding flash attributes in methods with a ModelAndView return value
|
||||
* preserve quotes in MediaType parameters
|
||||
* make flash attributes available in the model of ParameterizableViewController and UrlFilenameViewController
|
||||
|
||||
Changes in version 3.1 GA (2011-12-12)
|
||||
--------------------------------------
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2011 the original author or authors.
|
||||
* Copyright 2002-2012 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.
|
||||
|
|
@ -34,6 +34,8 @@ import javax.jms.MessageConsumer;
|
|||
import javax.jms.MessageProducer;
|
||||
import javax.jms.QueueSession;
|
||||
import javax.jms.Session;
|
||||
import javax.jms.TemporaryQueue;
|
||||
import javax.jms.TemporaryTopic;
|
||||
import javax.jms.Topic;
|
||||
import javax.jms.TopicSession;
|
||||
|
||||
|
|
@ -323,16 +325,18 @@ public class CachingConnectionFactory extends SingleConnectionFactory {
|
|||
// let raw JMS invocation throw an exception if Destination (i.e. args[0]) is null
|
||||
if ((methodName.equals("createConsumer") || methodName.equals("createReceiver") ||
|
||||
methodName.equals("createSubscriber"))) {
|
||||
if (args[0] != null) {
|
||||
return getCachedConsumer((Destination) args[0],
|
||||
Destination dest = (Destination) args[0];
|
||||
if (dest != null && !(dest instanceof TemporaryQueue || dest instanceof TemporaryTopic)) {
|
||||
return getCachedConsumer(dest,
|
||||
(args.length > 1 ? (String) args[1] : null),
|
||||
(args.length > 2 && (Boolean) args[2]),
|
||||
null);
|
||||
}
|
||||
}
|
||||
else if (methodName.equals("createDurableSubscriber")) {
|
||||
if (args[0] != null) {
|
||||
return getCachedConsumer((Destination) args[0],
|
||||
Destination dest = (Destination) args[0];
|
||||
if (dest != null) {
|
||||
return getCachedConsumer(dest,
|
||||
(args.length > 2 ? (String) args[2] : null),
|
||||
(args.length > 3 && (Boolean) args[3]),
|
||||
(String) args[1]);
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2011 the original author or authors.
|
||||
* Copyright 2002-2012 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.
|
||||
|
|
@ -151,6 +151,7 @@ public abstract class AbstractJmsListeningContainer extends JmsDestinationAccess
|
|||
/**
|
||||
* Delegates to {@link #validateConfiguration()} and {@link #initialize()}.
|
||||
*/
|
||||
@Override
|
||||
public void afterPropertiesSet() {
|
||||
super.afterPropertiesSet();
|
||||
validateConfiguration();
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2011 the original author or authors.
|
||||
* Copyright 2002-2012 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.
|
||||
|
|
@ -410,6 +410,7 @@ public abstract class AbstractMessageListenerContainer extends AbstractJmsListen
|
|||
return this.acceptMessagesWhileStopping;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void validateConfiguration() {
|
||||
if (this.destination == null) {
|
||||
throw new IllegalArgumentException("Property 'destination' or 'destinationName' is required");
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2010 the original author or authors.
|
||||
* Copyright 2002-2012 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.
|
||||
|
|
@ -75,8 +75,7 @@ import org.springframework.transaction.support.TransactionSynchronizationUtils;
|
|||
* @see #receiveAndExecute
|
||||
* @see #setTransactionManager
|
||||
*/
|
||||
public abstract class AbstractPollingMessageListenerContainer extends AbstractMessageListenerContainer
|
||||
implements BeanNameAware {
|
||||
public abstract class AbstractPollingMessageListenerContainer extends AbstractMessageListenerContainer {
|
||||
|
||||
/**
|
||||
* The default receive timeout: 1000 ms = 1 second.
|
||||
|
|
@ -100,6 +99,7 @@ public abstract class AbstractPollingMessageListenerContainer extends AbstractMe
|
|||
private volatile Boolean commitAfterNoMessageReceived;
|
||||
|
||||
|
||||
@Override
|
||||
public void setSessionTransacted(boolean sessionTransacted) {
|
||||
super.setSessionTransacted(sessionTransacted);
|
||||
this.sessionTransactedCalled = true;
|
||||
|
|
@ -188,6 +188,7 @@ public abstract class AbstractPollingMessageListenerContainer extends AbstractMe
|
|||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void initialize() {
|
||||
// Set sessionTransacted=true in case of a non-JTA transaction manager.
|
||||
if (!this.sessionTransactedCalled &&
|
||||
|
|
@ -374,6 +375,7 @@ public abstract class AbstractPollingMessageListenerContainer extends AbstractMe
|
|||
* container's "sessionTransacted" flag being set to "true".
|
||||
* @see org.springframework.jms.connection.JmsResourceHolder
|
||||
*/
|
||||
@Override
|
||||
protected boolean isSessionLocallyTransacted(Session session) {
|
||||
if (!super.isSessionLocallyTransacted(session)) {
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2011 the original author or authors.
|
||||
* Copyright 2002-2012 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.
|
||||
|
|
@ -470,6 +470,7 @@ public class DefaultMessageListenerContainer extends AbstractPollingMessageListe
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void validateConfiguration() {
|
||||
super.validateConfiguration();
|
||||
synchronized (this.lifecycleMonitor) {
|
||||
|
|
@ -484,6 +485,7 @@ public class DefaultMessageListenerContainer extends AbstractPollingMessageListe
|
|||
// Implementation of AbstractMessageListenerContainer's template methods
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
@Override
|
||||
public void initialize() {
|
||||
// Adapt default cache level.
|
||||
if (this.cacheLevel == CACHE_AUTO) {
|
||||
|
|
@ -516,6 +518,7 @@ public class DefaultMessageListenerContainer extends AbstractPollingMessageListe
|
|||
* @see #scheduleNewInvoker
|
||||
* @see #setTaskExecutor
|
||||
*/
|
||||
@Override
|
||||
protected void doInitialize() throws JMSException {
|
||||
synchronized (this.lifecycleMonitor) {
|
||||
for (int i = 0; i < this.concurrentConsumers; i++) {
|
||||
|
|
@ -527,6 +530,7 @@ public class DefaultMessageListenerContainer extends AbstractPollingMessageListe
|
|||
/**
|
||||
* Destroy the registered JMS Sessions and associated MessageConsumers.
|
||||
*/
|
||||
@Override
|
||||
protected void doShutdown() throws JMSException {
|
||||
logger.debug("Waiting for shutdown of message listener invokers");
|
||||
try {
|
||||
|
|
@ -549,6 +553,7 @@ public class DefaultMessageListenerContainer extends AbstractPollingMessageListe
|
|||
/**
|
||||
* Overridden to reset the stop callback, if any.
|
||||
*/
|
||||
@Override
|
||||
public void start() throws JmsException {
|
||||
synchronized (this.lifecycleMonitor) {
|
||||
this.stopCallback = null;
|
||||
|
|
@ -658,6 +663,7 @@ public class DefaultMessageListenerContainer extends AbstractPollingMessageListe
|
|||
* @see #setCacheLevel
|
||||
* @see #CACHE_CONNECTION
|
||||
*/
|
||||
@Override
|
||||
protected final boolean sharedConnectionEnabled() {
|
||||
return (getCacheLevel() >= CACHE_CONNECTION);
|
||||
}
|
||||
|
|
@ -666,6 +672,7 @@ public class DefaultMessageListenerContainer extends AbstractPollingMessageListe
|
|||
* Re-executes the given task via this listener container's TaskExecutor.
|
||||
* @see #setTaskExecutor
|
||||
*/
|
||||
@Override
|
||||
protected void doRescheduleTask(Object task) {
|
||||
this.taskExecutor.execute((Runnable) task);
|
||||
}
|
||||
|
|
@ -674,6 +681,7 @@ public class DefaultMessageListenerContainer extends AbstractPollingMessageListe
|
|||
* Tries scheduling a new invoker, since we know messages are coming in...
|
||||
* @see #scheduleNewInvokerIfAppropriate()
|
||||
*/
|
||||
@Override
|
||||
protected void messageReceived(Object invoker, Session session) {
|
||||
((AsyncMessageListenerInvoker) invoker).setIdle(false);
|
||||
scheduleNewInvokerIfAppropriate();
|
||||
|
|
@ -682,6 +690,7 @@ public class DefaultMessageListenerContainer extends AbstractPollingMessageListe
|
|||
/**
|
||||
* Marks the affected invoker as idle.
|
||||
*/
|
||||
@Override
|
||||
protected void noMessageReceived(Object invoker, Session session) {
|
||||
((AsyncMessageListenerInvoker) invoker).setIdle(true);
|
||||
}
|
||||
|
|
@ -745,6 +754,7 @@ public class DefaultMessageListenerContainer extends AbstractPollingMessageListe
|
|||
* asynchronous invokers to establish the shared Connection on first access.
|
||||
* @see #refreshConnectionUntilSuccessful()
|
||||
*/
|
||||
@Override
|
||||
protected void establishSharedConnection() {
|
||||
try {
|
||||
super.establishSharedConnection();
|
||||
|
|
@ -760,6 +770,7 @@ public class DefaultMessageListenerContainer extends AbstractPollingMessageListe
|
|||
* <code>Connection.start()</code>, relying on listeners to perform
|
||||
* appropriate recovery.
|
||||
*/
|
||||
@Override
|
||||
protected void startSharedConnection() {
|
||||
try {
|
||||
super.startSharedConnection();
|
||||
|
|
@ -774,6 +785,7 @@ public class DefaultMessageListenerContainer extends AbstractPollingMessageListe
|
|||
* <code>Connection.stop()</code>, relying on listeners to perform
|
||||
* appropriate recovery after a restart.
|
||||
*/
|
||||
@Override
|
||||
protected void stopSharedConnection() {
|
||||
try {
|
||||
super.stopSharedConnection();
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2010 the original author or authors.
|
||||
* Copyright 2002-2012 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.
|
||||
|
|
@ -62,6 +62,8 @@ public class SimpleMessageListenerContainer extends AbstractMessageListenerConta
|
|||
|
||||
private boolean pubSubNoLocal = false;
|
||||
|
||||
private boolean connectLazily = false;
|
||||
|
||||
private int concurrentConsumers = 1;
|
||||
|
||||
private Executor taskExecutor;
|
||||
|
|
@ -89,6 +91,20 @@ public class SimpleMessageListenerContainer extends AbstractMessageListenerConta
|
|||
return this.pubSubNoLocal;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify whether to connect lazily, i.e. whether to establish the JMS Connection
|
||||
* and the corresponding Sessions and MessageConsumers as late as possible -
|
||||
* in the start phase of this container.
|
||||
* <p>Default is "false": connecting early, i.e. during the bean initialization phase.
|
||||
* Set this flag to "true" in order to switch to lazy connecting if your target broker
|
||||
* is likely to not have started up yet and you prefer to not even try a connection.
|
||||
* @see #start()
|
||||
* @see #initialize()
|
||||
*/
|
||||
public void setConnectLazily(boolean connectLazily) {
|
||||
this.connectLazily = connectLazily;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify concurrency limits via a "lower-upper" String, e.g. "5-10", or a simple
|
||||
* upper limit String, e.g. "10".
|
||||
|
|
@ -159,6 +175,7 @@ public class SimpleMessageListenerContainer extends AbstractMessageListenerConta
|
|||
this.taskExecutor = taskExecutor;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void validateConfiguration() {
|
||||
super.validateConfiguration();
|
||||
if (isSubscriptionDurable() && this.concurrentConsumers != 1) {
|
||||
|
|
@ -174,6 +191,7 @@ public class SimpleMessageListenerContainer extends AbstractMessageListenerConta
|
|||
/**
|
||||
* Always use a shared JMS Connection.
|
||||
*/
|
||||
@Override
|
||||
protected final boolean sharedConnectionEnabled() {
|
||||
return true;
|
||||
}
|
||||
|
|
@ -183,15 +201,25 @@ public class SimpleMessageListenerContainer extends AbstractMessageListenerConta
|
|||
* in the form of a JMS Session plus associated MessageConsumer.
|
||||
* @see #createListenerConsumer
|
||||
*/
|
||||
@Override
|
||||
protected void doInitialize() throws JMSException {
|
||||
establishSharedConnection();
|
||||
initializeConsumers();
|
||||
if (!this.connectLazily) {
|
||||
try {
|
||||
establishSharedConnection();
|
||||
}
|
||||
catch (JMSException ex) {
|
||||
logger.debug("Could not connect on initialization - registering message consumers lazily", ex);
|
||||
return;
|
||||
}
|
||||
initializeConsumers();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Re-initializes this container's JMS message consumers,
|
||||
* if not initialized already.
|
||||
*/
|
||||
@Override
|
||||
protected void doStart() throws JMSException {
|
||||
super.doStart();
|
||||
initializeConsumers();
|
||||
|
|
@ -200,6 +228,7 @@ public class SimpleMessageListenerContainer extends AbstractMessageListenerConta
|
|||
/**
|
||||
* Registers this listener container as JMS ExceptionListener on the shared connection.
|
||||
*/
|
||||
@Override
|
||||
protected void prepareSharedConnection(Connection connection) throws JMSException {
|
||||
super.prepareSharedConnection(connection);
|
||||
connection.setExceptionListener(this);
|
||||
|
|
@ -320,6 +349,7 @@ public class SimpleMessageListenerContainer extends AbstractMessageListenerConta
|
|||
/**
|
||||
* Destroy the registered JMS Sessions and associated MessageConsumers.
|
||||
*/
|
||||
@Override
|
||||
protected void doShutdown() throws JMSException {
|
||||
logger.debug("Closing JMS MessageConsumers");
|
||||
for (MessageConsumer consumer : this.consumers) {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2010 the original author or authors.
|
||||
* Copyright 2002-2012 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.
|
||||
|
|
@ -787,7 +787,7 @@ public class LocalSessionFactoryBean extends AbstractSessionFactoryBean implemen
|
|||
configTimeTransactionManagerHolder.remove();
|
||||
}
|
||||
if (this.cacheRegionFactory != null) {
|
||||
configTimeCacheProviderHolder.remove();
|
||||
configTimeRegionFactoryHolder.remove();
|
||||
}
|
||||
if (this.cacheProvider != null) {
|
||||
configTimeCacheProviderHolder.remove();
|
||||
|
|
@ -862,7 +862,7 @@ public class LocalSessionFactoryBean extends AbstractSessionFactoryBean implemen
|
|||
|
||||
/**
|
||||
* Return the Configuration object used to build the SessionFactory.
|
||||
* Allows access to configuration metadata stored there (rarely needed).
|
||||
* Allows for access to configuration metadata stored there (rarely needed).
|
||||
* @throws IllegalStateException if the Configuration object has not been initialized yet
|
||||
*/
|
||||
public final Configuration getConfiguration() {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2011 the original author or authors.
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
|
@ -23,6 +23,7 @@ import javax.sql.DataSource;
|
|||
|
||||
import org.hibernate.Interceptor;
|
||||
import org.hibernate.SessionFactory;
|
||||
import org.hibernate.cfg.Configuration;
|
||||
import org.hibernate.cfg.NamingStrategy;
|
||||
|
||||
import org.springframework.beans.factory.DisposableBean;
|
||||
|
|
@ -37,16 +38,15 @@ import org.springframework.core.io.support.ResourcePatternResolver;
|
|||
import org.springframework.core.io.support.ResourcePatternUtils;
|
||||
|
||||
/**
|
||||
* {@link org.springframework.beans.factory.FactoryBean} that creates a
|
||||
* Hibernate {@link org.hibernate.SessionFactory}. This is the usual way to
|
||||
* set up a shared Hibernate SessionFactory in a Spring application context;
|
||||
* the SessionFactory can then be passed to Hibernate-based DAOs via
|
||||
* dependency injection.
|
||||
* {@link org.springframework.beans.factory.FactoryBean} that creates a Hibernate
|
||||
* {@link org.hibernate.SessionFactory}. This is the usual way to set up a shared
|
||||
* Hibernate SessionFactory in a Spring application context; the SessionFactory can
|
||||
* then be passed to Hibernate-based data access objects via dependency injection.
|
||||
*
|
||||
* <p><b>NOTE:</b> This variant of LocalSessionFactoryBean requires Hibernate 4.0
|
||||
* or higher. It is similar in role to the same-named class in the <code>orm.hibernate3</code>
|
||||
* package. However, in practice, it is closer to <code>AnnotationSessionFactoryBean</code>
|
||||
* since its core purpose is to bootstrap a <code>SessionFactory</code> from annotation scanning.
|
||||
* <p><b>NOTE:</b> This variant of LocalSessionFactoryBean requires Hibernate 4.0 or higher.
|
||||
* It is similar in role to the same-named class in the <code>orm.hibernate3</code> package.
|
||||
* However, in practice, it is closer to <code>AnnotationSessionFactoryBean</code> since
|
||||
* its core purpose is to bootstrap a <code>SessionFactory</code> from annotation scanning.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 3.1
|
||||
|
|
@ -84,6 +84,8 @@ public class LocalSessionFactoryBean extends HibernateExceptionTranslator
|
|||
|
||||
private ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver();
|
||||
|
||||
private Configuration configuration;
|
||||
|
||||
private SessionFactory sessionFactory;
|
||||
|
||||
|
||||
|
|
@ -328,7 +330,36 @@ public class LocalSessionFactoryBean extends HibernateExceptionTranslator
|
|||
sfb.scanPackages(this.packagesToScan);
|
||||
}
|
||||
|
||||
this.sessionFactory = sfb.buildSessionFactory();
|
||||
// Build SessionFactory instance.
|
||||
this.configuration = sfb;
|
||||
this.sessionFactory = buildSessionFactory(sfb);
|
||||
}
|
||||
|
||||
/**
|
||||
* Subclasses can override this method to perform custom initialization
|
||||
* of the SessionFactory instance, creating it via the given Configuration
|
||||
* object that got prepared by this LocalSessionFactoryBean.
|
||||
* <p>The default implementation invokes LocalSessionFactoryBuilder's buildSessionFactory.
|
||||
* A custom implementation could prepare the instance in a specific way (e.g. applying
|
||||
* a custom ServiceRegistry) or use a custom SessionFactoryImpl subclass.
|
||||
* @param sfb LocalSessionFactoryBuilder prepared by this LocalSessionFactoryBean
|
||||
* @return the SessionFactory instance
|
||||
* @see LocalSessionFactoryBuilder#buildSessionFactory
|
||||
*/
|
||||
protected SessionFactory buildSessionFactory(LocalSessionFactoryBuilder sfb) {
|
||||
return sfb.buildSessionFactory();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the Hibernate Configuration object used to build the SessionFactory.
|
||||
* Allows for access to configuration metadata stored there (rarely needed).
|
||||
* @throws IllegalStateException if the Configuration object has not been initialized yet
|
||||
*/
|
||||
public final Configuration getConfiguration() {
|
||||
if (this.configuration == null) {
|
||||
throw new IllegalStateException("Configuration not initialized yet");
|
||||
}
|
||||
return this.configuration;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,120 @@
|
|||
/*
|
||||
* Copyright 2002-2012 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.oxm.jaxb;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import javax.xml.bind.annotation.XmlEnum;
|
||||
import javax.xml.bind.annotation.XmlRootElement;
|
||||
import javax.xml.bind.annotation.XmlSeeAlso;
|
||||
import javax.xml.bind.annotation.XmlType;
|
||||
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.core.io.ResourceLoader;
|
||||
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
|
||||
import org.springframework.core.io.support.ResourcePatternResolver;
|
||||
import org.springframework.core.io.support.ResourcePatternUtils;
|
||||
import org.springframework.core.type.classreading.CachingMetadataReaderFactory;
|
||||
import org.springframework.core.type.classreading.MetadataReader;
|
||||
import org.springframework.core.type.classreading.MetadataReaderFactory;
|
||||
import org.springframework.core.type.filter.AnnotationTypeFilter;
|
||||
import org.springframework.core.type.filter.TypeFilter;
|
||||
import org.springframework.oxm.UncategorizedMappingException;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
||||
/**
|
||||
* Helper class for {@link Jaxb2Marshaller} that scans given packages for classes marked with JAXB2 annotations.
|
||||
*
|
||||
* @author Arjen Poutsma
|
||||
* @author David Harrigan
|
||||
* @see #scanPackages()
|
||||
*/
|
||||
class ClassPathJaxb2TypeScanner {
|
||||
|
||||
private static final String RESOURCE_PATTERN = "/**/*.class";
|
||||
|
||||
private final TypeFilter[] jaxb2TypeFilters =
|
||||
new TypeFilter[]{new AnnotationTypeFilter(XmlRootElement.class, false),
|
||||
new AnnotationTypeFilter(XmlType.class, false), new AnnotationTypeFilter(XmlSeeAlso.class, false),
|
||||
new AnnotationTypeFilter(XmlEnum.class, false)};
|
||||
|
||||
private final String[] packagesToScan;
|
||||
|
||||
private ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver();
|
||||
|
||||
private List<Class<?>> jaxb2Classes = new ArrayList<Class<?>>();
|
||||
|
||||
/** Constructs a new {@code ClassPathJaxb2TypeScanner} for the given packages. */
|
||||
ClassPathJaxb2TypeScanner(String[] packagesToScan) {
|
||||
Assert.notEmpty(packagesToScan, "'packagesToScan' must not be empty");
|
||||
this.packagesToScan = packagesToScan;
|
||||
}
|
||||
|
||||
void setResourceLoader(ResourceLoader resourceLoader) {
|
||||
if (resourceLoader != null) {
|
||||
this.resourcePatternResolver = ResourcePatternUtils.getResourcePatternResolver(resourceLoader);
|
||||
}
|
||||
}
|
||||
|
||||
/** Returns the JAXB2 classes found in the specified packages. */
|
||||
Class<?>[] getJaxb2Classes() {
|
||||
return jaxb2Classes.toArray(new Class<?>[jaxb2Classes.size()]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Scans the packages for classes marked with JAXB2 annotations.
|
||||
*
|
||||
* @throws UncategorizedMappingException in case of errors
|
||||
*/
|
||||
void scanPackages() throws UncategorizedMappingException {
|
||||
try {
|
||||
for (String packageToScan : packagesToScan) {
|
||||
String pattern = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
|
||||
ClassUtils.convertClassNameToResourcePath(packageToScan) + RESOURCE_PATTERN;
|
||||
Resource[] resources = resourcePatternResolver.getResources(pattern);
|
||||
MetadataReaderFactory metadataReaderFactory = new CachingMetadataReaderFactory(resourcePatternResolver);
|
||||
for (Resource resource : resources) {
|
||||
MetadataReader metadataReader = metadataReaderFactory.getMetadataReader(resource);
|
||||
if (isJaxb2Class(metadataReader, metadataReaderFactory)) {
|
||||
String className = metadataReader.getClassMetadata().getClassName();
|
||||
Class<?> jaxb2AnnotatedClass = resourcePatternResolver.getClassLoader().loadClass(className);
|
||||
jaxb2Classes.add(jaxb2AnnotatedClass);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (IOException ex) {
|
||||
throw new UncategorizedMappingException("Failed to scan classpath for unlisted classes", ex);
|
||||
}
|
||||
catch (ClassNotFoundException ex) {
|
||||
throw new UncategorizedMappingException("Failed to load annotated classes from classpath", ex);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isJaxb2Class(MetadataReader reader, MetadataReaderFactory factory) throws IOException {
|
||||
for (TypeFilter filter : jaxb2TypeFilters) {
|
||||
if (filter.match(reader, factory)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2011 the original author or authors.
|
||||
* Copyright 2002-2012 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,7 +16,7 @@
|
|||
|
||||
package org.springframework.oxm.jaxb;
|
||||
|
||||
import java.awt.Image;
|
||||
import java.awt.*;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
|
@ -65,10 +65,20 @@ import javax.xml.transform.sax.SAXSource;
|
|||
import javax.xml.validation.Schema;
|
||||
import javax.xml.validation.SchemaFactory;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.w3c.dom.ls.LSResourceResolver;
|
||||
import org.xml.sax.InputSource;
|
||||
import org.xml.sax.SAXException;
|
||||
import org.xml.sax.XMLReader;
|
||||
import org.xml.sax.helpers.XMLReaderFactory;
|
||||
|
||||
import org.springframework.beans.factory.BeanClassLoaderAware;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.context.ResourceLoaderAware;
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.core.io.ResourceLoader;
|
||||
import org.springframework.oxm.GenericMarshaller;
|
||||
import org.springframework.oxm.GenericUnmarshaller;
|
||||
import org.springframework.oxm.MarshallingFailureException;
|
||||
|
|
@ -87,14 +97,6 @@ import org.springframework.util.ObjectUtils;
|
|||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.util.xml.StaxUtils;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.w3c.dom.ls.LSResourceResolver;
|
||||
import org.xml.sax.InputSource;
|
||||
import org.xml.sax.SAXException;
|
||||
import org.xml.sax.XMLReader;
|
||||
import org.xml.sax.helpers.XMLReaderFactory;
|
||||
|
||||
/**
|
||||
* Implementation of the <code>Marshaller</code> interface for JAXB 2.0.
|
||||
*
|
||||
|
|
@ -117,7 +119,7 @@ import org.xml.sax.helpers.XMLReaderFactory;
|
|||
*/
|
||||
public class Jaxb2Marshaller
|
||||
implements MimeMarshaller, MimeUnmarshaller, GenericMarshaller, GenericUnmarshaller, BeanClassLoaderAware,
|
||||
InitializingBean {
|
||||
ResourceLoaderAware, InitializingBean {
|
||||
|
||||
private static final String CID = "cid:";
|
||||
|
||||
|
|
@ -130,6 +132,8 @@ public class Jaxb2Marshaller
|
|||
private String contextPath;
|
||||
|
||||
private Class<?>[] classesToBeBound;
|
||||
|
||||
private String[] packagesToScan;
|
||||
|
||||
private Map<String, ?> jaxbContextProperties;
|
||||
|
||||
|
|
@ -153,6 +157,8 @@ public class Jaxb2Marshaller
|
|||
|
||||
private ClassLoader beanClassLoader;
|
||||
|
||||
private ResourceLoader resourceLoader;
|
||||
|
||||
private JAXBContext jaxbContext;
|
||||
|
||||
private Schema schema;
|
||||
|
|
@ -161,7 +167,7 @@ public class Jaxb2Marshaller
|
|||
|
||||
private boolean supportJaxbElementClass = false;
|
||||
|
||||
private LSResourceResolver schemaResourceResolver;
|
||||
private LSResourceResolver schemaResourceResolver;
|
||||
|
||||
|
||||
/**
|
||||
|
|
@ -175,6 +181,8 @@ public class Jaxb2Marshaller
|
|||
|
||||
/**
|
||||
* Set a JAXB context path.
|
||||
* <p>Setting this property, {@link #setClassesToBeBound "classesToBeBound"}, or
|
||||
* {@link #setPackagesToScan "packagesToScan"} is required.
|
||||
*/
|
||||
public void setContextPath(String contextPath) {
|
||||
Assert.hasText(contextPath, "'contextPath' must not be null");
|
||||
|
|
@ -190,7 +198,8 @@ public class Jaxb2Marshaller
|
|||
|
||||
/**
|
||||
* Set the list of Java classes to be recognized by a newly created JAXBContext.
|
||||
* Setting this property or {@link #setContextPath "contextPath"} is required.
|
||||
* <p>Setting this property, {@link #setContextPath "contextPath"}, or
|
||||
* {@link #setPackagesToScan "packagesToScan"} is required.
|
||||
*/
|
||||
public void setClassesToBeBound(Class<?>... classesToBeBound) {
|
||||
Assert.notEmpty(classesToBeBound, "'classesToBeBound' must not be empty");
|
||||
|
|
@ -204,6 +213,23 @@ public class Jaxb2Marshaller
|
|||
return this.classesToBeBound;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the packages to search using Spring-based scanning for classes with JAXB2 annotations in the classpath.
|
||||
* <p>Setting this property, {@link #setContextPath "contextPath"}, or
|
||||
* {@link #setClassesToBeBound "classesToBeBound"} is required. This is analogous to Spring's component-scan feature
|
||||
* ({@link org.springframework.context.annotation.ClassPathBeanDefinitionScanner}).
|
||||
*/
|
||||
public void setPackagesToScan(String[] packagesToScan) {
|
||||
this.packagesToScan = packagesToScan;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the packages to search for JAXB2 annotations.
|
||||
*/
|
||||
public String[] getPackagesToScan() {
|
||||
return packagesToScan;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the <code>JAXBContext</code> properties. These implementation-specific
|
||||
* properties will be set on the underlying <code>JAXBContext</code>.
|
||||
|
|
@ -289,17 +315,18 @@ public class Jaxb2Marshaller
|
|||
this.schemaLanguage = schemaLanguage;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the resource resolver, as used to load the schema resources.
|
||||
* @see SchemaFactory#setResourceResolver(org.w3c.dom.ls.LSResourceResolver)
|
||||
* @see #setSchema(Resource)
|
||||
* @see #setSchemas(Resource[])
|
||||
*/
|
||||
public void setSchemaResourceResolver(LSResourceResolver schemaResourceResolver) {
|
||||
this.schemaResourceResolver = schemaResourceResolver;
|
||||
}
|
||||
/**
|
||||
* Sets the resource resolver, as used to load the schema resources.
|
||||
*
|
||||
* @see SchemaFactory#setResourceResolver(org.w3c.dom.ls.LSResourceResolver)
|
||||
* @see #setSchema(Resource)
|
||||
* @see #setSchemas(Resource[])
|
||||
*/
|
||||
public void setSchemaResourceResolver(LSResourceResolver schemaResourceResolver) {
|
||||
this.schemaResourceResolver = schemaResourceResolver;
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* Specify whether MTOM support should be enabled or not.
|
||||
* Default is <code>false</code>: marshalling using XOP/MTOM not being enabled.
|
||||
*/
|
||||
|
|
@ -336,13 +363,23 @@ public class Jaxb2Marshaller
|
|||
this.beanClassLoader = classLoader;
|
||||
}
|
||||
|
||||
public void setResourceLoader(ResourceLoader resourceLoader) {
|
||||
this.resourceLoader = resourceLoader;
|
||||
}
|
||||
|
||||
public final void afterPropertiesSet() throws Exception {
|
||||
if (StringUtils.hasLength(getContextPath()) && !ObjectUtils.isEmpty(getClassesToBeBound())) {
|
||||
throw new IllegalArgumentException("Specify either 'contextPath' or 'classesToBeBound property'; not both");
|
||||
boolean hasContextPath = StringUtils.hasLength(getContextPath());
|
||||
boolean hasClassesToBeBound = !ObjectUtils.isEmpty(getClassesToBeBound());
|
||||
boolean hasPackagesToScan = !ObjectUtils.isEmpty(getPackagesToScan());
|
||||
|
||||
if (hasContextPath && (hasClassesToBeBound || hasPackagesToScan) ||
|
||||
(hasClassesToBeBound && hasPackagesToScan)) {
|
||||
throw new IllegalArgumentException("Specify either 'contextPath', 'classesToBeBound', " +
|
||||
"or 'packagesToScan'");
|
||||
}
|
||||
else if (!StringUtils.hasLength(getContextPath()) && ObjectUtils.isEmpty(getClassesToBeBound())) {
|
||||
throw new IllegalArgumentException("Setting either 'contextPath' or 'classesToBeBound' is required");
|
||||
if (!hasContextPath && !hasClassesToBeBound && !hasPackagesToScan) {
|
||||
throw new IllegalArgumentException(
|
||||
"Setting either 'contextPath', 'classesToBeBound', " + "or 'packagesToScan' is required");
|
||||
}
|
||||
if (!this.lazyInit) {
|
||||
getJaxbContext();
|
||||
|
|
@ -361,6 +398,9 @@ public class Jaxb2Marshaller
|
|||
else if (!ObjectUtils.isEmpty(getClassesToBeBound())) {
|
||||
this.jaxbContext = createJaxbContextFromClasses();
|
||||
}
|
||||
else if (!ObjectUtils.isEmpty(getPackagesToScan())) {
|
||||
this.jaxbContext = createJaxbContextFromPackages();
|
||||
}
|
||||
}
|
||||
catch (JAXBException ex) {
|
||||
throw convertJaxbException(ex);
|
||||
|
|
@ -404,6 +444,26 @@ public class Jaxb2Marshaller
|
|||
}
|
||||
}
|
||||
|
||||
private JAXBContext createJaxbContextFromPackages() throws JAXBException {
|
||||
if (logger.isInfoEnabled()) {
|
||||
logger.info("Creating JAXBContext by scanning packages [" +
|
||||
StringUtils.arrayToCommaDelimitedString(getPackagesToScan()) + "]");
|
||||
}
|
||||
ClassPathJaxb2TypeScanner scanner = new ClassPathJaxb2TypeScanner(getPackagesToScan());
|
||||
scanner.setResourceLoader(this.resourceLoader);
|
||||
scanner.scanPackages();
|
||||
Class<?>[] jaxb2Classes = scanner.getJaxb2Classes();
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Found JAXB2 classes: [" + StringUtils.arrayToCommaDelimitedString(jaxb2Classes) + "]");
|
||||
}
|
||||
if (this.jaxbContextProperties != null) {
|
||||
return JAXBContext.newInstance(jaxb2Classes, this.jaxbContextProperties);
|
||||
}
|
||||
else {
|
||||
return JAXBContext.newInstance(jaxb2Classes);
|
||||
}
|
||||
}
|
||||
|
||||
private Schema loadSchema(Resource[] resources, String schemaLanguage) throws IOException, SAXException {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Setting validation schema to " + StringUtils.arrayToCommaDelimitedString(this.schemaResources));
|
||||
|
|
@ -420,9 +480,9 @@ public class Jaxb2Marshaller
|
|||
schemaSources[i] = new SAXSource(xmlReader, inputSource);
|
||||
}
|
||||
SchemaFactory schemaFactory = SchemaFactory.newInstance(schemaLanguage);
|
||||
if (schemaResourceResolver != null) {
|
||||
schemaFactory.setResourceResolver(schemaResourceResolver);
|
||||
}
|
||||
if (schemaResourceResolver != null) {
|
||||
schemaFactory.setResourceResolver(schemaResourceResolver);
|
||||
}
|
||||
return schemaFactory.newSchema(schemaSources);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2011 the original author or authors.
|
||||
* Copyright 2002-2012 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.
|
||||
|
|
@ -279,6 +279,13 @@ public class Jaxb2MarshallerTests extends AbstractMarshallerTests {
|
|||
assertTrue("No XML written", writer.toString().length() > 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void supportsPackagesToScan() throws Exception {
|
||||
marshaller = new Jaxb2Marshaller();
|
||||
marshaller.setPackagesToScan(new String[] {CONTEXT_PATH});
|
||||
marshaller.afterPropertiesSet();
|
||||
}
|
||||
|
||||
@XmlRootElement
|
||||
public static class DummyRootElement {
|
||||
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ Import-Template:
|
|||
org.exolab.castor.*;version="[1.2.0, 2.0.0)";resolution:=optional,
|
||||
org.jibx.runtime.*;version="[1.1.5, 2.0.0)";resolution:=optional,
|
||||
org.springframework.beans.*;version=${spring.osgi.range},
|
||||
org.springframework.context.*;version=${spring.osgi.range},
|
||||
org.springframework.core.*;version=${spring.osgi.range},
|
||||
org.springframework.util.*;version=${spring.osgi.range},
|
||||
org.w3c.dom.*;version="0",
|
||||
|
|
|
|||
|
|
@ -815,7 +815,7 @@ public class DispatcherServlet extends FrameworkServlet {
|
|||
}
|
||||
}
|
||||
|
||||
this.flashMapManager.requestStarted(request);
|
||||
this.flashMapManager.requestStarted(request, response);
|
||||
|
||||
// Make framework objects available to handlers and view objects.
|
||||
request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, getWebApplicationContext());
|
||||
|
|
@ -827,7 +827,7 @@ public class DispatcherServlet extends FrameworkServlet {
|
|||
doDispatch(request, response);
|
||||
}
|
||||
finally {
|
||||
this.flashMapManager.requestCompleted(request);
|
||||
this.flashMapManager.requestCompleted(request, response);
|
||||
|
||||
// Restore the original attribute snapshot, in case of an include.
|
||||
if (attributesSnapshot != null) {
|
||||
|
|
|
|||
|
|
@ -63,6 +63,8 @@ public final class FlashMap extends HashMap<String, Object> implements Comparabl
|
|||
/**
|
||||
* Create a new instance with an id uniquely identifying the creator of
|
||||
* this FlashMap.
|
||||
* @param createdBy identifies the FlashMapManager instance that created
|
||||
* and will manage this FlashMap instance (e.g. via a hashCode)
|
||||
*/
|
||||
public FlashMap(int createdBy) {
|
||||
this.createdBy = createdBy;
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@
|
|||
package org.springframework.web.servlet;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
/**
|
||||
* A strategy interface for storing, retrieving, and managing {@code FlashMap}
|
||||
|
|
@ -64,8 +65,9 @@ public interface FlashMapManager {
|
|||
* <li>Clean expired FlashMap instances.
|
||||
* </ol>
|
||||
* @param request the current request
|
||||
* @param response the current response
|
||||
*/
|
||||
void requestStarted(HttpServletRequest request);
|
||||
void requestStarted(HttpServletRequest request, HttpServletResponse response);
|
||||
|
||||
/**
|
||||
* Start the expiration period of the "output" FlashMap save it in the
|
||||
|
|
@ -73,7 +75,8 @@ public interface FlashMapManager {
|
|||
* <p>The "output" FlashMap should not be saved if it is empty or if it was
|
||||
* not created by the current FlashMapManager instance.
|
||||
* @param request the current request
|
||||
* @param response the current response
|
||||
*/
|
||||
void requestCompleted(HttpServletRequest request);
|
||||
void requestCompleted(HttpServletRequest request, HttpServletResponse response);
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,13 +23,14 @@ import org.springframework.web.method.HandlerMethod;
|
|||
import org.springframework.web.servlet.ModelAndView;
|
||||
|
||||
/**
|
||||
* Abstract base class for {@link org.springframework.web.servlet.HandlerExceptionResolver HandlerExceptionResolver}
|
||||
* implementations that support handling exceptions from {@link HandlerMethod}s rather than handlers.
|
||||
* Abstract base class for
|
||||
* {@link org.springframework.web.servlet.HandlerExceptionResolver HandlerExceptionResolver}
|
||||
* implementations that support handling exceptions from handlers of type {@link HandlerMethod}.
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
* @since 3.1
|
||||
*/
|
||||
public class AbstractHandlerMethodExceptionResolver extends AbstractHandlerExceptionResolver {
|
||||
public abstract class AbstractHandlerMethodExceptionResolver extends AbstractHandlerExceptionResolver {
|
||||
|
||||
/**
|
||||
* Checks if the handler is a {@link HandlerMethod} instance and performs the check against the bean
|
||||
|
|
@ -52,10 +53,10 @@ public class AbstractHandlerMethodExceptionResolver extends AbstractHandlerExcep
|
|||
}
|
||||
|
||||
@Override
|
||||
protected final ModelAndView doResolveException(HttpServletRequest request,
|
||||
HttpServletResponse response,
|
||||
Object handler,
|
||||
Exception ex) {
|
||||
protected final ModelAndView doResolveException(
|
||||
HttpServletRequest request, HttpServletResponse response,
|
||||
Object handler, Exception ex) {
|
||||
|
||||
return doResolveHandlerMethodException(request, response, (HandlerMethod) handler, ex);
|
||||
}
|
||||
|
||||
|
|
@ -73,11 +74,8 @@ public class AbstractHandlerMethodExceptionResolver extends AbstractHandlerExcep
|
|||
* @param ex the exception that got thrown during handler execution
|
||||
* @return a corresponding ModelAndView to forward to, or <code>null</code> for default processing
|
||||
*/
|
||||
protected ModelAndView doResolveHandlerMethodException(HttpServletRequest request,
|
||||
HttpServletResponse response,
|
||||
HandlerMethod handlerMethod,
|
||||
Exception ex) {
|
||||
return null;
|
||||
}
|
||||
|
||||
protected abstract ModelAndView doResolveHandlerMethodException(
|
||||
HttpServletRequest request, HttpServletResponse response,
|
||||
HandlerMethod handlerMethod, Exception ex);
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ import javax.servlet.http.HttpServletResponse;
|
|||
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.web.servlet.ModelAndView;
|
||||
import org.springframework.web.servlet.support.RequestContextUtils;
|
||||
import org.springframework.web.util.UrlPathHelper;
|
||||
|
||||
/**
|
||||
|
|
@ -86,7 +87,8 @@ public abstract class AbstractUrlViewController extends AbstractController {
|
|||
|
||||
/**
|
||||
* Retrieves the URL path to use for lookup and delegates to
|
||||
* {@link #getViewNameForRequest}.
|
||||
* {@link #getViewNameForRequest}. Also adds the content of
|
||||
* {@link RequestContextUtils#getInputFlashMap} to the model.
|
||||
*/
|
||||
@Override
|
||||
protected ModelAndView handleRequestInternal(HttpServletRequest request, HttpServletResponse response) {
|
||||
|
|
@ -95,7 +97,7 @@ public abstract class AbstractUrlViewController extends AbstractController {
|
|||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Returning view name '" + viewName + "' for lookup path [" + lookupPath + "]");
|
||||
}
|
||||
return new ModelAndView(viewName);
|
||||
return new ModelAndView(viewName, RequestContextUtils.getInputFlashMap(request));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ import javax.servlet.http.HttpServletRequest;
|
|||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.springframework.web.servlet.ModelAndView;
|
||||
import org.springframework.web.servlet.support.RequestContextUtils;
|
||||
|
||||
/**
|
||||
* <p>Trivial controller that always returns a named view. The view
|
||||
|
|
@ -87,12 +88,13 @@ public class ParameterizableViewController extends AbstractController {
|
|||
|
||||
/**
|
||||
* Return a ModelAndView object with the specified view name.
|
||||
* The content of {@link RequestContextUtils#getInputFlashMap} is also added to the model.
|
||||
* @see #getViewName()
|
||||
*/
|
||||
@Override
|
||||
protected ModelAndView handleRequestInternal(HttpServletRequest request, HttpServletResponse response)
|
||||
throws Exception {
|
||||
return new ModelAndView(getViewName());
|
||||
return new ModelAndView(getViewName(), RequestContextUtils.getInputFlashMap(request));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -173,7 +173,7 @@ public final class ProducesRequestCondition extends AbstractRequestCondition<Pro
|
|||
* <ol>
|
||||
* <li>Sort 'Accept' header media types by quality value via
|
||||
* {@link MediaType#sortByQualityValue(List)} and iterate the list.
|
||||
* <li>Get the lowest index of matching media types from each "produces"
|
||||
* <li>Get the first index of matching media types in each "produces"
|
||||
* condition first matching with {@link MediaType#equals(Object)} and
|
||||
* then with {@link MediaType#includes(MediaType)}.
|
||||
* <li>If a lower index is found, the condition at that index wins.
|
||||
|
|
@ -220,7 +220,9 @@ public final class ProducesRequestCondition extends AbstractRequestCondition<Pro
|
|||
|
||||
private int indexOfEqualMediaType(MediaType mediaType) {
|
||||
for (int i = 0; i < getExpressionsToCompare().size(); i++) {
|
||||
if (mediaType.equals(getExpressionsToCompare().get(i).getMediaType())) {
|
||||
MediaType currentMediaType = getExpressionsToCompare().get(i).getMediaType();
|
||||
if (mediaType.getType().equalsIgnoreCase(currentMediaType.getType()) &&
|
||||
mediaType.getSubtype().equalsIgnoreCase(currentMediaType.getSubtype())) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2011 the original author or authors.
|
||||
* Copyright 2002-2012 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.
|
||||
|
|
@ -39,13 +39,13 @@ import org.springframework.web.method.support.ModelAndViewContainer;
|
|||
|
||||
/**
|
||||
* Resolves {@link HttpEntity} method argument values and also handles
|
||||
* both {@link HttpEntity} and {@link ResponseEntity} return values.
|
||||
*
|
||||
* <p>An {@link HttpEntity} return type has a set purpose. Therefore this
|
||||
* handler should be configured ahead of handlers that support any return
|
||||
* both {@link HttpEntity} and {@link ResponseEntity} return values.
|
||||
*
|
||||
* <p>An {@link HttpEntity} return type has a set purpose. Therefore this
|
||||
* handler should be configured ahead of handlers that support any return
|
||||
* value type annotated with {@code @ModelAttribute} or {@code @ResponseBody}
|
||||
* to ensure they don't take over.
|
||||
*
|
||||
*
|
||||
* @author Arjen Poutsma
|
||||
* @author Rossen Stoyanchev
|
||||
* @since 3.1
|
||||
|
|
@ -66,10 +66,9 @@ public class HttpEntityMethodProcessor extends AbstractMessageConverterMethodPro
|
|||
return HttpEntity.class.equals(parameterType) || ResponseEntity.class.equals(parameterType);
|
||||
}
|
||||
|
||||
public Object resolveArgument(MethodParameter parameter,
|
||||
ModelAndViewContainer mavContainer,
|
||||
NativeWebRequest webRequest,
|
||||
WebDataBinderFactory binderFactory)
|
||||
public Object resolveArgument(
|
||||
MethodParameter parameter, ModelAndViewContainer mavContainer,
|
||||
NativeWebRequest webRequest, WebDataBinderFactory binderFactory)
|
||||
throws IOException, HttpMediaTypeNotSupportedException {
|
||||
|
||||
HttpInputMessage inputMessage = createInputMessage(webRequest);
|
||||
|
|
@ -100,11 +99,11 @@ public class HttpEntityMethodProcessor extends AbstractMessageConverterMethodPro
|
|||
+ "in method " + parameter.getMethod() + "is not parameterized");
|
||||
}
|
||||
|
||||
public void handleReturnValue(Object returnValue,
|
||||
MethodParameter returnType,
|
||||
ModelAndViewContainer mavContainer,
|
||||
NativeWebRequest webRequest) throws Exception {
|
||||
|
||||
public void handleReturnValue(
|
||||
Object returnValue, MethodParameter returnType,
|
||||
ModelAndViewContainer mavContainer, NativeWebRequest webRequest)
|
||||
throws Exception {
|
||||
|
||||
mavContainer.setRequestHandled(true);
|
||||
|
||||
if (returnValue == null) {
|
||||
|
|
@ -135,4 +134,4 @@ public class HttpEntityMethodProcessor extends AbstractMessageConverterMethodPro
|
|||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,15 +25,15 @@ import org.springframework.web.servlet.SmartView;
|
|||
import org.springframework.web.servlet.View;
|
||||
|
||||
/**
|
||||
* Handles return values of type {@link ModelAndView} copying view and model
|
||||
* Handles return values of type {@link ModelAndView} copying view and model
|
||||
* information to the {@link ModelAndViewContainer}.
|
||||
*
|
||||
* <p>If the return value is {@code null}, the
|
||||
* {@link ModelAndViewContainer#setRequestHandled(boolean)} flag is set to
|
||||
*
|
||||
* <p>If the return value is {@code null}, the
|
||||
* {@link ModelAndViewContainer#setRequestHandled(boolean)} flag is set to
|
||||
* {@code false} to indicate the request was handled directly.
|
||||
*
|
||||
* <p>A {@link ModelAndView} return type has a set purpose. Therefore this
|
||||
* handler should be configured ahead of handlers that support any return
|
||||
*
|
||||
* <p>A {@link ModelAndView} return type has a set purpose. Therefore this
|
||||
* handler should be configured ahead of handlers that support any return
|
||||
* value type annotated with {@code @ModelAttribute} or {@code @ResponseBody}
|
||||
* to ensure they don't take over.
|
||||
*
|
||||
|
|
@ -41,20 +41,21 @@ import org.springframework.web.servlet.View;
|
|||
* @since 3.1
|
||||
*/
|
||||
public class ModelAndViewMethodReturnValueHandler implements HandlerMethodReturnValueHandler {
|
||||
|
||||
|
||||
public boolean supportsReturnType(MethodParameter returnType) {
|
||||
return ModelAndView.class.isAssignableFrom(returnType.getParameterType());
|
||||
}
|
||||
|
||||
public void handleReturnValue(Object returnValue,
|
||||
MethodParameter returnType,
|
||||
ModelAndViewContainer mavContainer,
|
||||
NativeWebRequest webRequest) throws Exception {
|
||||
public void handleReturnValue(
|
||||
Object returnValue, MethodParameter returnType,
|
||||
ModelAndViewContainer mavContainer, NativeWebRequest webRequest)
|
||||
throws Exception {
|
||||
|
||||
if (returnValue == null) {
|
||||
mavContainer.setRequestHandled(true);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
ModelAndView mav = (ModelAndView) returnValue;
|
||||
if (mav.isReference()) {
|
||||
String viewName = mav.getViewName();
|
||||
|
|
@ -75,4 +76,4 @@ public class ModelAndViewMethodReturnValueHandler implements HandlerMethodReturn
|
|||
mavContainer.addAllAttributes(mav.getModel());
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2011 the original author or authors.
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
|
@ -29,25 +29,25 @@ import org.springframework.web.servlet.ModelAndView;
|
|||
import org.springframework.web.servlet.mvc.annotation.ModelAndViewResolver;
|
||||
|
||||
/**
|
||||
* This return value handler is intended to be ordered after all others as it
|
||||
* This return value handler is intended to be ordered after all others as it
|
||||
* attempts to handle _any_ return value type (i.e. returns {@code true} for
|
||||
* all return types).
|
||||
*
|
||||
*
|
||||
* <p>The return value is handled either with a {@link ModelAndViewResolver}
|
||||
* or otherwise by regarding it as a model attribute if it is a non-simple
|
||||
* type. If neither of these succeeds (essentially simple type other than
|
||||
* or otherwise by regarding it as a model attribute if it is a non-simple
|
||||
* type. If neither of these succeeds (essentially simple type other than
|
||||
* String), {@link UnsupportedOperationException} is raised.
|
||||
*
|
||||
* <p><strong>Note:</strong> This class is primarily needed to support
|
||||
*
|
||||
* <p><strong>Note:</strong> This class is primarily needed to support
|
||||
* {@link ModelAndViewResolver}, which unfortunately cannot be properly
|
||||
* adapted to the {@link HandlerMethodReturnValueHandler} contract since the
|
||||
* adapted to the {@link HandlerMethodReturnValueHandler} contract since the
|
||||
* {@link HandlerMethodReturnValueHandler#supportsReturnType} method
|
||||
* cannot be implemented. Hence {@code ModelAndViewResolver}s are limited
|
||||
* to always being invoked at the end after all other return value
|
||||
* handlers have been given a chance. It is recommended to re-implement
|
||||
* to always being invoked at the end after all other return value
|
||||
* handlers have been given a chance. It is recommended to re-implement
|
||||
* a {@code ModelAndViewResolver} as {@code HandlerMethodReturnValueHandler},
|
||||
* which also provides better access to the return type and method information.
|
||||
*
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
* @since 3.1
|
||||
*/
|
||||
|
|
@ -71,10 +71,10 @@ public class ModelAndViewResolverMethodReturnValueHandler implements HandlerMeth
|
|||
return true;
|
||||
}
|
||||
|
||||
public void handleReturnValue(Object returnValue,
|
||||
MethodParameter returnType,
|
||||
ModelAndViewContainer mavContainer,
|
||||
NativeWebRequest request) throws Exception {
|
||||
public void handleReturnValue(
|
||||
Object returnValue, MethodParameter returnType,
|
||||
ModelAndViewContainer mavContainer, NativeWebRequest request)
|
||||
throws Exception {
|
||||
|
||||
if (this.mavResolvers != null) {
|
||||
for (ModelAndViewResolver mavResolver : this.mavResolvers) {
|
||||
|
|
@ -93,7 +93,7 @@ public class ModelAndViewResolverMethodReturnValueHandler implements HandlerMeth
|
|||
}
|
||||
}
|
||||
|
||||
// No suitable ModelAndViewResolver..
|
||||
// No suitable ModelAndViewResolver..
|
||||
|
||||
if (this.modelAttributeProcessor.supportsReturnType(returnType)) {
|
||||
this.modelAttributeProcessor.handleReturnValue(returnValue, returnType, mavContainer, request);
|
||||
|
|
@ -104,4 +104,4 @@ public class ModelAndViewResolverMethodReturnValueHandler implements HandlerMeth
|
|||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2011 the original author or authors.
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
|
@ -30,8 +30,8 @@ import org.springframework.web.servlet.mvc.support.RedirectAttributes;
|
|||
import org.springframework.web.servlet.mvc.support.RedirectAttributesModelMap;
|
||||
|
||||
/**
|
||||
* Resolves method arguments of type {@link RedirectAttributes}.
|
||||
*
|
||||
* Resolves method arguments of type {@link RedirectAttributes}.
|
||||
*
|
||||
* <p>This resolver must be listed ahead of {@link org.springframework.web.method.annotation.ModelMethodProcessor} and
|
||||
* {@link org.springframework.web.method.annotation.MapMethodProcessor}, which support {@link Map} and {@link Model}
|
||||
* arguments both of which are "super" types of {@code RedirectAttributes}
|
||||
|
|
@ -46,10 +46,11 @@ public class RedirectAttributesMethodArgumentResolver implements HandlerMethodAr
|
|||
return RedirectAttributes.class.isAssignableFrom(parameter.getParameterType());
|
||||
}
|
||||
|
||||
public Object resolveArgument(MethodParameter parameter,
|
||||
ModelAndViewContainer mavContainer,
|
||||
NativeWebRequest webRequest,
|
||||
WebDataBinderFactory binderFactory) throws Exception {
|
||||
public Object resolveArgument(
|
||||
MethodParameter parameter, ModelAndViewContainer mavContainer,
|
||||
NativeWebRequest webRequest, WebDataBinderFactory binderFactory)
|
||||
throws Exception {
|
||||
|
||||
DataBinder dataBinder = binderFactory.createBinder(webRequest, null, null);
|
||||
ModelMap redirectAttributes = new RedirectAttributesModelMap(dataBinder);
|
||||
mavContainer.setRedirectModel(redirectAttributes);
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2011 the original author or authors.
|
||||
* Copyright 2002-2012 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.
|
||||
|
|
@ -89,9 +89,9 @@ public class ServletInvocableHandlerMethod extends InvocableHandlerMethod {
|
|||
* @param mavContainer the {@link ModelAndViewContainer} for the current request
|
||||
* @param providedArgs argument values to try to use without the need for view resolution
|
||||
*/
|
||||
public final void invokeAndHandle(NativeWebRequest request,
|
||||
ModelAndViewContainer mavContainer,
|
||||
Object...providedArgs) throws Exception {
|
||||
public final void invokeAndHandle(
|
||||
NativeWebRequest request, ModelAndViewContainer mavContainer,
|
||||
Object... providedArgs) throws Exception {
|
||||
|
||||
Object returnValue = invokeForRequest(request, mavContainer, providedArgs);
|
||||
|
||||
|
|
@ -124,7 +124,7 @@ public class ServletInvocableHandlerMethod extends InvocableHandlerMethod {
|
|||
sb.append("[value=" + returnValue + "]");
|
||||
return getDetailedErrorMessage(sb.toString());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set the response status according to the {@link ResponseStatus} annotation.
|
||||
*/
|
||||
|
|
@ -157,4 +157,4 @@ public class ServletInvocableHandlerMethod extends InvocableHandlerMethod {
|
|||
private boolean hasResponseStatus() {
|
||||
return responseStatus != null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2011 the original author or authors.
|
||||
* Copyright 2002-2012 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.
|
||||
|
|
@ -37,7 +37,7 @@ import org.springframework.web.multipart.MultipartRequest;
|
|||
import org.springframework.web.servlet.support.RequestContextUtils;
|
||||
|
||||
/**
|
||||
* Resolves request-related method argument values of the following types:
|
||||
* Resolves request-related method argument values of the following types:
|
||||
* <ul>
|
||||
* <li>{@link WebRequest}
|
||||
* <li>{@link ServletRequest}
|
||||
|
|
@ -57,20 +57,20 @@ public class ServletRequestMethodArgumentResolver implements HandlerMethodArgume
|
|||
|
||||
public boolean supportsParameter(MethodParameter parameter) {
|
||||
Class<?> paramType = parameter.getParameterType();
|
||||
return WebRequest.class.isAssignableFrom(paramType) ||
|
||||
return WebRequest.class.isAssignableFrom(paramType) ||
|
||||
ServletRequest.class.isAssignableFrom(paramType) ||
|
||||
MultipartRequest.class.isAssignableFrom(paramType) ||
|
||||
HttpSession.class.isAssignableFrom(paramType) ||
|
||||
HttpSession.class.isAssignableFrom(paramType) ||
|
||||
Principal.class.isAssignableFrom(paramType) ||
|
||||
Locale.class.equals(paramType) ||
|
||||
Locale.class.equals(paramType) ||
|
||||
InputStream.class.isAssignableFrom(paramType) ||
|
||||
Reader.class.isAssignableFrom(paramType);
|
||||
}
|
||||
|
||||
public Object resolveArgument(MethodParameter parameter,
|
||||
ModelAndViewContainer mavContainer,
|
||||
NativeWebRequest webRequest,
|
||||
WebDataBinderFactory binderFactory) throws IOException {
|
||||
public Object resolveArgument(
|
||||
MethodParameter parameter, ModelAndViewContainer mavContainer,
|
||||
NativeWebRequest webRequest, WebDataBinderFactory binderFactory)
|
||||
throws IOException {
|
||||
|
||||
Class<?> paramType = parameter.getParameterType();
|
||||
if (WebRequest.class.isAssignableFrom(paramType)) {
|
||||
|
|
@ -108,4 +108,4 @@ public class ServletRequestMethodArgumentResolver implements HandlerMethodArgume
|
|||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2011 the original author or authors.
|
||||
* Copyright 2002-2012 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.
|
||||
|
|
@ -47,20 +47,20 @@ public class ServletResponseMethodArgumentResolver implements HandlerMethodArgum
|
|||
public boolean supportsParameter(MethodParameter parameter) {
|
||||
Class<?> paramType = parameter.getParameterType();
|
||||
return ServletResponse.class.isAssignableFrom(paramType)
|
||||
|| OutputStream.class.isAssignableFrom(paramType)
|
||||
|| OutputStream.class.isAssignableFrom(paramType)
|
||||
|| Writer.class.isAssignableFrom(paramType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set {@link ModelAndViewContainer#setRequestHandled(boolean)} to
|
||||
* {@code false} to indicate that the method signature provides access
|
||||
* to the response. If subsequently the underlying method returns
|
||||
* Set {@link ModelAndViewContainer#setRequestHandled(boolean)} to
|
||||
* {@code false} to indicate that the method signature provides access
|
||||
* to the response. If subsequently the underlying method returns
|
||||
* {@code null}, the request is considered directly handled.
|
||||
*/
|
||||
public Object resolveArgument(MethodParameter parameter,
|
||||
ModelAndViewContainer mavContainer,
|
||||
NativeWebRequest webRequest,
|
||||
WebDataBinderFactory binderFactory) throws IOException {
|
||||
public Object resolveArgument(
|
||||
MethodParameter parameter, ModelAndViewContainer mavContainer,
|
||||
NativeWebRequest webRequest, WebDataBinderFactory binderFactory)
|
||||
throws IOException {
|
||||
|
||||
mavContainer.setRequestHandled(true);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2011 the original author or authors.
|
||||
* Copyright 2002-2012 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.
|
||||
|
|
@ -28,7 +28,7 @@ import org.springframework.web.util.UriComponentsBuilder;
|
|||
|
||||
/**
|
||||
* Resolvers argument values of type {@link UriComponentsBuilder}.
|
||||
*
|
||||
*
|
||||
* <p>The returned instance is initialized via
|
||||
* {@link ServletUriComponentsBuilder#fromServletMapping(HttpServletRequest)}.
|
||||
*
|
||||
|
|
@ -41,11 +41,11 @@ public class UriComponentsBuilderMethodArgumentResolver implements HandlerMethod
|
|||
return UriComponentsBuilder.class.isAssignableFrom(parameter.getParameterType());
|
||||
}
|
||||
|
||||
public Object resolveArgument(MethodParameter parameter,
|
||||
ModelAndViewContainer mavContainer,
|
||||
NativeWebRequest webRequest,
|
||||
WebDataBinderFactory binderFactory) throws Exception {
|
||||
|
||||
public Object resolveArgument(
|
||||
MethodParameter parameter, ModelAndViewContainer mavContainer,
|
||||
NativeWebRequest webRequest, WebDataBinderFactory binderFactory)
|
||||
throws Exception {
|
||||
|
||||
HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class);
|
||||
return ServletUriComponentsBuilder.fromServletMapping(request);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2011 the original author or authors.
|
||||
* Copyright 2002-2012 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.
|
||||
|
|
@ -27,14 +27,14 @@ import org.springframework.web.servlet.View;
|
|||
/**
|
||||
* Handles return values that are of type {@link View}.
|
||||
*
|
||||
* <p>A {@code null} return value is left as-is leaving it to the configured
|
||||
* {@link RequestToViewNameTranslator} to select a view name by convention.
|
||||
* <p>A {@code null} return value is left as-is leaving it to the configured
|
||||
* {@link RequestToViewNameTranslator} to select a view name by convention.
|
||||
*
|
||||
* <p>A {@link View} return type has a set purpose. Therefore this handler
|
||||
* should be configured ahead of handlers that support any return value type
|
||||
* <p>A {@link View} return type has a set purpose. Therefore this handler
|
||||
* should be configured ahead of handlers that support any return value type
|
||||
* annotated with {@code @ModelAttribute} or {@code @ResponseBody} to ensure
|
||||
* they don't take over.
|
||||
*
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
* @since 3.1
|
||||
*/
|
||||
|
|
@ -44,10 +44,11 @@ public class ViewMethodReturnValueHandler implements HandlerMethodReturnValueHan
|
|||
return View.class.isAssignableFrom(returnType.getParameterType());
|
||||
}
|
||||
|
||||
public void handleReturnValue(Object returnValue,
|
||||
MethodParameter returnType,
|
||||
ModelAndViewContainer mavContainer,
|
||||
NativeWebRequest webRequest) throws Exception {
|
||||
public void handleReturnValue(
|
||||
Object returnValue, MethodParameter returnType,
|
||||
ModelAndViewContainer mavContainer, NativeWebRequest webRequest)
|
||||
throws Exception {
|
||||
|
||||
if (returnValue == null) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -62,7 +63,7 @@ public class ViewMethodReturnValueHandler implements HandlerMethodReturnValueHan
|
|||
}
|
||||
else {
|
||||
// should not happen
|
||||
throw new UnsupportedOperationException("Unexpected return type: " +
|
||||
throw new UnsupportedOperationException("Unexpected return type: " +
|
||||
returnType.getParameterType().getName() + " in method: " + returnType.getMethod());
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2011 the original author or authors.
|
||||
* Copyright 2002-2012 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.
|
||||
|
|
@ -26,12 +26,12 @@ import org.springframework.web.servlet.RequestToViewNameTranslator;
|
|||
* Handles return values of types {@code void} and {@code String} interpreting
|
||||
* them as view name reference.
|
||||
*
|
||||
* <p>A {@code null} return value, either due to a {@code void} return type or
|
||||
* as the actual return value is left as-is allowing the configured
|
||||
* <p>A {@code null} return value, either due to a {@code void} return type or
|
||||
* as the actual return value is left as-is allowing the configured
|
||||
* {@link RequestToViewNameTranslator} to select a view name by convention.
|
||||
*
|
||||
* <p>A String return value can be interpreted in more than one ways depending
|
||||
* on the presence of annotations like {@code @ModelAttribute} or
|
||||
* <p>A String return value can be interpreted in more than one ways depending
|
||||
* on the presence of annotations like {@code @ModelAttribute} or
|
||||
* {@code @ResponseBody}. Therefore this handler should be configured after
|
||||
* the handlers that support these annotations.
|
||||
*
|
||||
|
|
@ -45,10 +45,11 @@ public class ViewNameMethodReturnValueHandler implements HandlerMethodReturnValu
|
|||
return (void.class.equals(paramType) || String.class.equals(paramType));
|
||||
}
|
||||
|
||||
public void handleReturnValue(Object returnValue,
|
||||
MethodParameter returnType,
|
||||
ModelAndViewContainer mavContainer,
|
||||
NativeWebRequest webRequest) throws Exception {
|
||||
public void handleReturnValue(
|
||||
Object returnValue, MethodParameter returnType,
|
||||
ModelAndViewContainer mavContainer, NativeWebRequest webRequest)
|
||||
throws Exception {
|
||||
|
||||
if (returnValue == null) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -61,7 +62,7 @@ public class ViewNameMethodReturnValueHandler implements HandlerMethodReturnValu
|
|||
}
|
||||
else {
|
||||
// should not happen
|
||||
throw new UnsupportedOperationException("Unexpected return type: " +
|
||||
throw new UnsupportedOperationException("Unexpected return type: " +
|
||||
returnType.getParameterType().getName() + " in method: " + returnType.getMethod());
|
||||
}
|
||||
}
|
||||
|
|
@ -69,7 +70,7 @@ public class ViewNameMethodReturnValueHandler implements HandlerMethodReturnValu
|
|||
/**
|
||||
* Whether the given view name is a redirect view reference.
|
||||
* @param viewName the view name to check, never {@code null}
|
||||
* @return "true" if the given view name is recognized as a redirect view
|
||||
* @return "true" if the given view name is recognized as a redirect view
|
||||
* reference; "false" otherwise.
|
||||
*/
|
||||
protected boolean isRedirectViewName(String viewName) {
|
||||
|
|
|
|||
|
|
@ -22,10 +22,12 @@ import java.util.List;
|
|||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.servlet.http.HttpSession;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
|
@ -47,24 +49,46 @@ public class DefaultFlashMapManager implements FlashMapManager {
|
|||
|
||||
private static final Log logger = LogFactory.getLog(DefaultFlashMapManager.class);
|
||||
|
||||
private int flashTimeout = 180;
|
||||
private int flashMapTimeout = 180;
|
||||
|
||||
private final UrlPathHelper urlPathHelper = new UrlPathHelper();
|
||||
private UrlPathHelper urlPathHelper = new UrlPathHelper();
|
||||
|
||||
/**
|
||||
* Set the amount of time in seconds after a {@link FlashMap} is saved
|
||||
* (at request completion) and before it expires.
|
||||
* <p>The default value is 180 seconds.
|
||||
*/
|
||||
public void setFlashMapTimeout(int flashTimeout) {
|
||||
this.flashTimeout = flashTimeout;
|
||||
public void setFlashMapTimeout(int flashMapTimeout) {
|
||||
this.flashMapTimeout = flashMapTimeout;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the amount of time in seconds before a FlashMap expires.
|
||||
*/
|
||||
public int getFlashMapTimeout() {
|
||||
return flashMapTimeout;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the UrlPathHelper to use to obtain the request URI.
|
||||
*/
|
||||
public void setUrlPathHelper(UrlPathHelper urlPathHelper) {
|
||||
Assert.notNull(urlPathHelper, "UrlPathHelper must not be null");
|
||||
this.urlPathHelper = urlPathHelper;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the UrlPathHelper implementation for the request URI.
|
||||
*/
|
||||
public UrlPathHelper getUrlPathHelper() {
|
||||
return urlPathHelper;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* <p>An HTTP session is never created by this method.
|
||||
*/
|
||||
public void requestStarted(HttpServletRequest request) {
|
||||
public final void requestStarted(HttpServletRequest request, HttpServletResponse response) {
|
||||
if (request.getAttribute(OUTPUT_FLASH_MAP_ATTRIBUTE) != null) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -164,9 +188,9 @@ public class DefaultFlashMapManager implements FlashMapManager {
|
|||
}
|
||||
|
||||
/**
|
||||
* Iterate all flash maps and remove expired ones.
|
||||
* Check and remove expired FlashMaps instances.
|
||||
*/
|
||||
private void removeExpiredFlashMaps(HttpServletRequest request) {
|
||||
protected void removeExpiredFlashMaps(HttpServletRequest request) {
|
||||
List<FlashMap> allMaps = retrieveFlashMaps(request, false);
|
||||
if (CollectionUtils.isEmpty(allMaps)) {
|
||||
return;
|
||||
|
|
@ -189,7 +213,7 @@ public class DefaultFlashMapManager implements FlashMapManager {
|
|||
* {@inheritDoc}
|
||||
* <p>An HTTP session is never created if the "output" FlashMap is empty.
|
||||
*/
|
||||
public void requestCompleted(HttpServletRequest request) {
|
||||
public void requestCompleted(HttpServletRequest request, HttpServletResponse response) {
|
||||
FlashMap flashMap = (FlashMap) request.getAttribute(OUTPUT_FLASH_MAP_ATTRIBUTE);
|
||||
if (flashMap == null) {
|
||||
throw new IllegalStateException("requestCompleted called but \"output\" FlashMap was never created");
|
||||
|
|
@ -198,24 +222,35 @@ public class DefaultFlashMapManager implements FlashMapManager {
|
|||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Saving FlashMap=" + flashMap);
|
||||
}
|
||||
onSaveFlashMap(flashMap, request);
|
||||
retrieveFlashMaps(request, true).add(flashMap);
|
||||
onSaveFlashMap(flashMap, request, response);
|
||||
saveFlashMap(flashMap, request, response);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update a FlashMap before it is stored in the HTTP Session.
|
||||
* Update a FlashMap before it is stored in the underlying storage.
|
||||
* <p>The default implementation starts the expiration period and ensures the
|
||||
* target request path is decoded and normalized if it is relative.
|
||||
* @param flashMap the flash map to be saved
|
||||
* @param request the current request
|
||||
* @param response the current response
|
||||
*/
|
||||
protected void onSaveFlashMap(FlashMap flashMap, HttpServletRequest request) {
|
||||
protected void onSaveFlashMap(FlashMap flashMap, HttpServletRequest request, HttpServletResponse response) {
|
||||
String targetPath = flashMap.getTargetRequestPath();
|
||||
flashMap.setTargetRequestPath(decodeAndNormalizePath(targetPath, request));
|
||||
flashMap.startExpirationPeriod(this.flashTimeout);
|
||||
flashMap.startExpirationPeriod(this.flashMapTimeout);
|
||||
}
|
||||
|
||||
/**
|
||||
* Save the FlashMap in the underlying storage.
|
||||
* @param flashMap the FlashMap to save
|
||||
* @param request the current request
|
||||
* @param response the current response
|
||||
*/
|
||||
protected void saveFlashMap(FlashMap flashMap, HttpServletRequest request, HttpServletResponse response) {
|
||||
retrieveFlashMaps(request, true).add(flashMap);
|
||||
}
|
||||
|
||||
private String decodeAndNormalizePath(String path, HttpServletRequest request) {
|
||||
if (path != null) {
|
||||
path = this.urlPathHelper.decodeRequestString(request, path);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,71 @@
|
|||
/*
|
||||
* Copyright 2002-2012 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.web.servlet.mvc;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.mock.web.MockHttpServletRequest;
|
||||
import org.springframework.mock.web.MockHttpServletResponse;
|
||||
import org.springframework.ui.ModelMap;
|
||||
import org.springframework.web.servlet.FlashMapManager;
|
||||
import org.springframework.web.servlet.ModelAndView;
|
||||
|
||||
/**
|
||||
* Test fixture with a ParameterizableViewController.
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
* @since 3.1.1
|
||||
*/
|
||||
public class ParameterizableViewControllerTests {
|
||||
|
||||
private ParameterizableViewController controller;
|
||||
|
||||
private MockHttpServletRequest request;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
this.controller = new ParameterizableViewController();
|
||||
this.request = new MockHttpServletRequest("GET", "/");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void handleRequestWithViewName() throws Exception {
|
||||
String viewName = "testView";
|
||||
this.controller.setViewName(viewName);
|
||||
ModelAndView mav = this.controller.handleRequest(this.request, new MockHttpServletResponse());
|
||||
assertEquals(viewName, mav.getViewName());
|
||||
assertTrue(mav.getModel().isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void handleRequestWithoutViewName() throws Exception {
|
||||
ModelAndView mav = this.controller.handleRequest(this.request, new MockHttpServletResponse());
|
||||
assertNull(mav.getViewName());
|
||||
assertTrue(mav.getModel().isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void handleRequestWithFlashAttributes() throws Exception {
|
||||
this.request.setAttribute(FlashMapManager.INPUT_FLASH_MAP_ATTRIBUTE, new ModelMap("name", "value"));
|
||||
ModelAndView mav = this.controller.handleRequest(this.request, new MockHttpServletResponse());
|
||||
assertEquals(1, mav.getModel().size());
|
||||
assertEquals("value", mav.getModel().get("name"));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -20,8 +20,10 @@ import junit.framework.TestCase;
|
|||
|
||||
import org.springframework.mock.web.MockHttpServletRequest;
|
||||
import org.springframework.mock.web.MockHttpServletResponse;
|
||||
import org.springframework.ui.ModelMap;
|
||||
import org.springframework.util.AntPathMatcher;
|
||||
import org.springframework.util.PathMatcher;
|
||||
import org.springframework.web.servlet.FlashMapManager;
|
||||
import org.springframework.web.servlet.HandlerMapping;
|
||||
import org.springframework.web.servlet.ModelAndView;
|
||||
|
||||
|
|
@ -150,6 +152,17 @@ public class UrlFilenameViewControllerTests extends TestCase {
|
|||
assertTrue(mv.getModel().isEmpty());
|
||||
}
|
||||
|
||||
public void testWithFlashAttributes() throws Exception {
|
||||
UrlFilenameViewController ctrl = new UrlFilenameViewController();
|
||||
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/index");
|
||||
request.setAttribute(FlashMapManager.INPUT_FLASH_MAP_ATTRIBUTE, new ModelMap("name", "value"));
|
||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
ModelAndView mv = ctrl.handleRequest(request, response);
|
||||
assertEquals("index", mv.getViewName());
|
||||
assertEquals(1, mv.getModel().size());
|
||||
assertEquals("value", mv.getModel().get("name"));
|
||||
}
|
||||
|
||||
private void exposePathInMapping(MockHttpServletRequest request, String mapping) {
|
||||
String pathInMapping = this.pathMatcher.extractPathWithinPattern(mapping, request.getRequestURI());
|
||||
request.setAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE, pathInMapping);
|
||||
|
|
|
|||
|
|
@ -218,6 +218,20 @@ public class ProducesRequestConditionTests {
|
|||
assertTrue(condition2.compareTo(condition1, request) > 0);
|
||||
}
|
||||
|
||||
// SPR-9021
|
||||
|
||||
@Test
|
||||
public void compareToMediaTypeAllWithParameter() {
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
request.addHeader("Accept", "*/*;q=0.9");
|
||||
|
||||
ProducesRequestCondition condition1 = new ProducesRequestCondition();
|
||||
ProducesRequestCondition condition2 = new ProducesRequestCondition("application/json");
|
||||
|
||||
assertTrue(condition1.compareTo(condition2, request) < 0);
|
||||
assertTrue(condition2.compareTo(condition1, request) > 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void compareToEqualMatch() {
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ import org.springframework.web.servlet.view.RedirectView;
|
|||
|
||||
/**
|
||||
* Test fixture with {@link ModelAndViewMethodReturnValueHandler}.
|
||||
*
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
*/
|
||||
public class ModelAndViewMethodReturnValueHandlerTests {
|
||||
|
|
@ -57,7 +57,7 @@ public class ModelAndViewMethodReturnValueHandlerTests {
|
|||
this.webRequest = new ServletWebRequest(new MockHttpServletRequest());
|
||||
this.returnParamModelAndView = getReturnValueParam("modelAndView");
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void supportsReturnType() throws Exception {
|
||||
assertTrue(handler.supportsReturnType(returnParamModelAndView));
|
||||
|
|
@ -68,7 +68,7 @@ public class ModelAndViewMethodReturnValueHandlerTests {
|
|||
public void handleViewReference() throws Exception {
|
||||
ModelAndView mav = new ModelAndView("viewName", "attrName", "attrValue");
|
||||
handler.handleReturnValue(mav, returnParamModelAndView, mavContainer, webRequest);
|
||||
|
||||
|
||||
assertEquals("viewName", mavContainer.getView());
|
||||
assertEquals("attrValue", mavContainer.getModel().get("attrName"));
|
||||
}
|
||||
|
|
@ -77,7 +77,7 @@ public class ModelAndViewMethodReturnValueHandlerTests {
|
|||
public void handleViewInstance() throws Exception {
|
||||
ModelAndView mav = new ModelAndView(new RedirectView(), "attrName", "attrValue");
|
||||
handler.handleReturnValue(mav, returnParamModelAndView, mavContainer, webRequest);
|
||||
|
||||
|
||||
assertEquals(RedirectView.class, mavContainer.getView().getClass());
|
||||
assertEquals("attrValue", mavContainer.getModel().get("attrName"));
|
||||
}
|
||||
|
|
@ -85,7 +85,7 @@ public class ModelAndViewMethodReturnValueHandlerTests {
|
|||
@Test
|
||||
public void handleNull() throws Exception {
|
||||
handler.handleReturnValue(null, returnParamModelAndView, mavContainer, webRequest);
|
||||
|
||||
|
||||
assertTrue(mavContainer.isRequestHandled());
|
||||
}
|
||||
|
||||
|
|
@ -93,10 +93,10 @@ public class ModelAndViewMethodReturnValueHandlerTests {
|
|||
public void handleRedirectAttributesWithViewReference() throws Exception {
|
||||
RedirectAttributesModelMap redirectAttributes = new RedirectAttributesModelMap();
|
||||
mavContainer.setRedirectModel(redirectAttributes);
|
||||
|
||||
|
||||
ModelAndView mav = new ModelAndView(new RedirectView(), "attrName", "attrValue");
|
||||
handler.handleReturnValue(mav, returnParamModelAndView, mavContainer, webRequest);
|
||||
|
||||
|
||||
assertEquals(RedirectView.class, mavContainer.getView().getClass());
|
||||
assertEquals("attrValue", mavContainer.getModel().get("attrName"));
|
||||
assertSame("RedirectAttributes should be used if controller redirects", redirectAttributes,
|
||||
|
|
@ -107,24 +107,24 @@ public class ModelAndViewMethodReturnValueHandlerTests {
|
|||
public void handleRedirectAttributesWithViewInstance() throws Exception {
|
||||
RedirectAttributesModelMap redirectAttributes = new RedirectAttributesModelMap();
|
||||
mavContainer.setRedirectModel(redirectAttributes);
|
||||
|
||||
|
||||
ModelAndView mav = new ModelAndView("redirect:viewName", "attrName", "attrValue");
|
||||
handler.handleReturnValue(mav, returnParamModelAndView, mavContainer, webRequest);
|
||||
|
||||
|
||||
ModelMap model = mavContainer.getModel();
|
||||
assertEquals("redirect:viewName", mavContainer.getViewName());
|
||||
assertEquals("attrValue", model.get("attrName"));
|
||||
assertSame("RedirectAttributes should be used if controller redirects", redirectAttributes, model);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void handleRedirectAttributesWithoutRedirect() throws Exception {
|
||||
RedirectAttributesModelMap redirectAttributes = new RedirectAttributesModelMap();
|
||||
mavContainer.setRedirectModel(redirectAttributes);
|
||||
|
||||
|
||||
ModelAndView mav = new ModelAndView();
|
||||
handler.handleReturnValue(mav, returnParamModelAndView, mavContainer, webRequest);
|
||||
|
||||
|
||||
ModelMap model = mavContainer.getModel();
|
||||
assertEquals(null, mavContainer.getView());
|
||||
assertTrue(mavContainer.getModel().isEmpty());
|
||||
|
|
@ -136,7 +136,7 @@ public class ModelAndViewMethodReturnValueHandlerTests {
|
|||
Method method = getClass().getDeclaredMethod(methodName);
|
||||
return new MethodParameter(method, -1);
|
||||
}
|
||||
|
||||
|
||||
ModelAndView modelAndView() {
|
||||
return null;
|
||||
}
|
||||
|
|
@ -144,5 +144,5 @@ public class ModelAndViewMethodReturnValueHandlerTests {
|
|||
String viewName() {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@ import java.util.concurrent.CopyOnWriteArrayList;
|
|||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.mock.web.MockHttpServletRequest;
|
||||
import org.springframework.mock.web.MockHttpServletResponse;
|
||||
import org.springframework.web.servlet.FlashMap;
|
||||
import org.springframework.web.util.WebUtils;
|
||||
|
||||
|
|
@ -46,15 +47,18 @@ public class DefaultFlashMapManagerTests {
|
|||
|
||||
private MockHttpServletRequest request;
|
||||
|
||||
private MockHttpServletResponse response;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
this.flashMapManager = new DefaultFlashMapManager();
|
||||
this.request = new MockHttpServletRequest();
|
||||
this.response = new MockHttpServletResponse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void requestStarted() {
|
||||
this.flashMapManager.requestStarted(this.request);
|
||||
this.flashMapManager.requestStarted(this.request, this.response);
|
||||
FlashMap flashMap = RequestContextUtils.getOutputFlashMap(request);
|
||||
|
||||
assertNotNull("Current FlashMap not found", flashMap);
|
||||
|
|
@ -64,7 +68,7 @@ public class DefaultFlashMapManagerTests {
|
|||
public void requestStartedAlready() {
|
||||
FlashMap flashMap = new FlashMap();
|
||||
this.request.setAttribute(OUTPUT_FLASH_MAP_ATTRIBUTE, flashMap);
|
||||
this.flashMapManager.requestStarted(this.request);
|
||||
this.flashMapManager.requestStarted(this.request, this.response);
|
||||
|
||||
assertSame(flashMap, RequestContextUtils.getOutputFlashMap(request));
|
||||
}
|
||||
|
|
@ -79,7 +83,7 @@ public class DefaultFlashMapManagerTests {
|
|||
allMaps.add(flashMap);
|
||||
|
||||
this.request.setRequestURI("/path");
|
||||
this.flashMapManager.requestStarted(this.request);
|
||||
this.flashMapManager.requestStarted(this.request, this.response);
|
||||
|
||||
assertEquals(flashMap, RequestContextUtils.getInputFlashMap(this.request));
|
||||
assertEquals("Input FlashMap should have been removed", 0, getFlashMaps().size());
|
||||
|
|
@ -98,7 +102,7 @@ public class DefaultFlashMapManagerTests {
|
|||
|
||||
this.request.setAttribute(WebUtils.FORWARD_REQUEST_URI_ATTRIBUTE, "/accounts");
|
||||
this.request.setRequestURI("/mvc/accounts");
|
||||
this.flashMapManager.requestStarted(this.request);
|
||||
this.flashMapManager.requestStarted(this.request, this.response);
|
||||
|
||||
assertEquals(flashMap, RequestContextUtils.getInputFlashMap(this.request));
|
||||
assertEquals("Input FlashMap should have been removed", 0, getFlashMaps().size());
|
||||
|
|
@ -114,7 +118,7 @@ public class DefaultFlashMapManagerTests {
|
|||
allMaps.add(flashMap);
|
||||
|
||||
this.request.setRequestURI("/path/");
|
||||
this.flashMapManager.requestStarted(this.request);
|
||||
this.flashMapManager.requestStarted(this.request, this.response);
|
||||
|
||||
assertEquals(flashMap, RequestContextUtils.getInputFlashMap(this.request));
|
||||
assertEquals("Input FlashMap should have been removed", 0, getFlashMaps().size());
|
||||
|
|
@ -130,21 +134,21 @@ public class DefaultFlashMapManagerTests {
|
|||
allMaps.add(flashMap);
|
||||
|
||||
this.request.setParameter("number", (String) null);
|
||||
this.flashMapManager.requestStarted(this.request);
|
||||
this.flashMapManager.requestStarted(this.request, this.response);
|
||||
|
||||
assertNull(RequestContextUtils.getInputFlashMap(this.request));
|
||||
assertEquals("FlashMap should not have been removed", 1, getFlashMaps().size());
|
||||
|
||||
clearFlashMapRequestAttributes();
|
||||
this.request.setParameter("number", "two");
|
||||
this.flashMapManager.requestStarted(this.request);
|
||||
this.flashMapManager.requestStarted(this.request, this.response);
|
||||
|
||||
assertNull(RequestContextUtils.getInputFlashMap(this.request));
|
||||
assertEquals("FlashMap should not have been removed", 1, getFlashMaps().size());
|
||||
|
||||
clearFlashMapRequestAttributes();
|
||||
this.request.setParameter("number", "one");
|
||||
this.flashMapManager.requestStarted(this.request);
|
||||
this.flashMapManager.requestStarted(this.request, this.response);
|
||||
|
||||
assertEquals(flashMap, RequestContextUtils.getInputFlashMap(this.request));
|
||||
assertEquals("Input FlashMap should have been removed", 0, getFlashMaps().size());
|
||||
|
|
@ -163,14 +167,14 @@ public class DefaultFlashMapManagerTests {
|
|||
allMaps.add(flashMap);
|
||||
|
||||
this.request.setParameter("id", "1");
|
||||
this.flashMapManager.requestStarted(this.request);
|
||||
this.flashMapManager.requestStarted(this.request, this.response);
|
||||
|
||||
assertNull(RequestContextUtils.getInputFlashMap(this.request));
|
||||
assertEquals("FlashMap should not have been removed", 1, getFlashMaps().size());
|
||||
|
||||
clearFlashMapRequestAttributes();
|
||||
this.request.addParameter("id", "2");
|
||||
this.flashMapManager.requestStarted(this.request);
|
||||
this.flashMapManager.requestStarted(this.request, this.response);
|
||||
|
||||
assertEquals(flashMap, RequestContextUtils.getInputFlashMap(this.request));
|
||||
assertEquals("Input FlashMap should have been removed", 0, getFlashMaps().size());
|
||||
|
|
@ -196,7 +200,7 @@ public class DefaultFlashMapManagerTests {
|
|||
Collections.shuffle(allMaps);
|
||||
|
||||
this.request.setRequestURI("/one/two");
|
||||
this.flashMapManager.requestStarted(this.request);
|
||||
this.flashMapManager.requestStarted(this.request, this.response);
|
||||
|
||||
assertEquals(flashMapTwo, request.getAttribute(INPUT_FLASH_MAP_ATTRIBUTE));
|
||||
}
|
||||
|
|
@ -210,15 +214,15 @@ public class DefaultFlashMapManagerTests {
|
|||
flashMap.startExpirationPeriod(0);
|
||||
}
|
||||
Thread.sleep(100);
|
||||
this.flashMapManager.requestStarted(this.request);
|
||||
this.flashMapManager.requestStarted(this.request, this.response);
|
||||
|
||||
assertEquals(0, allMaps.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void saveFlashMapWithoutAttributes() throws InterruptedException {
|
||||
this.flashMapManager.requestStarted(this.request);
|
||||
this.flashMapManager.requestCompleted(this.request);
|
||||
this.flashMapManager.requestStarted(this.request, this.response);
|
||||
this.flashMapManager.requestCompleted(this.request, this.response);
|
||||
|
||||
assertNull(getFlashMaps());
|
||||
}
|
||||
|
|
@ -227,19 +231,19 @@ public class DefaultFlashMapManagerTests {
|
|||
public void saveFlashMapNotCreatedByThisManager() throws InterruptedException {
|
||||
FlashMap flashMap = new FlashMap();
|
||||
this.request.setAttribute(OUTPUT_FLASH_MAP_ATTRIBUTE, flashMap);
|
||||
this.flashMapManager.requestCompleted(this.request);
|
||||
this.flashMapManager.requestCompleted(this.request, this.response);
|
||||
|
||||
assertNull(getFlashMaps());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void saveFlashMapWithAttributes() throws InterruptedException {
|
||||
this.flashMapManager.requestStarted(this.request);
|
||||
this.flashMapManager.requestStarted(this.request, this.response);
|
||||
FlashMap flashMap = RequestContextUtils.getOutputFlashMap(this.request);
|
||||
flashMap.put("name", "value");
|
||||
|
||||
this.flashMapManager.setFlashMapTimeout(0);
|
||||
this.flashMapManager.requestCompleted(this.request);
|
||||
this.flashMapManager.requestCompleted(this.request, this.response);
|
||||
|
||||
Thread.sleep(100);
|
||||
|
||||
|
|
@ -252,49 +256,49 @@ public class DefaultFlashMapManagerTests {
|
|||
|
||||
@Test
|
||||
public void decodeTargetPath() throws InterruptedException {
|
||||
this.flashMapManager.requestStarted(this.request);
|
||||
this.flashMapManager.requestStarted(this.request, this.response);
|
||||
FlashMap flashMap = RequestContextUtils.getOutputFlashMap(this.request);
|
||||
flashMap.put("key", "value");
|
||||
|
||||
flashMap.setTargetRequestPath("/once%20upon%20a%20time");
|
||||
this.flashMapManager.requestCompleted(this.request);
|
||||
this.flashMapManager.requestCompleted(this.request, this.response);
|
||||
|
||||
assertEquals("/once upon a time", flashMap.getTargetRequestPath());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void normalizeTargetPath() throws InterruptedException {
|
||||
this.flashMapManager.requestStarted(this.request);
|
||||
this.flashMapManager.requestStarted(this.request, this.response);
|
||||
FlashMap flashMap = RequestContextUtils.getOutputFlashMap(this.request);
|
||||
flashMap.put("key", "value");
|
||||
|
||||
flashMap.setTargetRequestPath(".");
|
||||
this.request.setRequestURI("/once/upon/a/time");
|
||||
this.flashMapManager.requestCompleted(this.request);
|
||||
this.flashMapManager.requestCompleted(this.request, this.response);
|
||||
|
||||
assertEquals("/once/upon/a", flashMap.getTargetRequestPath());
|
||||
|
||||
flashMap.setTargetRequestPath("./");
|
||||
this.request.setRequestURI("/once/upon/a/time");
|
||||
this.flashMapManager.requestCompleted(this.request);
|
||||
this.flashMapManager.requestCompleted(this.request, this.response);
|
||||
|
||||
assertEquals("/once/upon/a/", flashMap.getTargetRequestPath());
|
||||
|
||||
flashMap.setTargetRequestPath("..");
|
||||
this.request.setRequestURI("/once/upon/a/time");
|
||||
this.flashMapManager.requestCompleted(this.request);
|
||||
this.flashMapManager.requestCompleted(this.request, this.response);
|
||||
|
||||
assertEquals("/once/upon", flashMap.getTargetRequestPath());
|
||||
|
||||
flashMap.setTargetRequestPath("../");
|
||||
this.request.setRequestURI("/once/upon/a/time");
|
||||
this.flashMapManager.requestCompleted(this.request);
|
||||
this.flashMapManager.requestCompleted(this.request, this.response);
|
||||
|
||||
assertEquals("/once/upon/", flashMap.getTargetRequestPath());
|
||||
|
||||
flashMap.setTargetRequestPath("../../only");
|
||||
this.request.setRequestURI("/once/upon/a/time");
|
||||
this.flashMapManager.requestCompleted(this.request);
|
||||
this.flashMapManager.requestCompleted(this.request, this.response);
|
||||
|
||||
assertEquals("/once/only", flashMap.getTargetRequestPath());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2010 the original author or authors.
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
|
@ -24,6 +24,7 @@ package org.springframework.http;
|
|||
* @author Arjen Poutsma
|
||||
* @see HttpStatus.Series
|
||||
* @see <a href="http://www.iana.org/assignments/http-status-codes">HTTP Status Code Registry</a>
|
||||
* @see <a href="http://en.wikipedia.org/wiki/List_of_HTTP_status_codes">List of HTTP status codes - Wikipedia</a>
|
||||
*/
|
||||
public enum HttpStatus {
|
||||
|
||||
|
|
@ -44,6 +45,12 @@ public enum HttpStatus {
|
|||
* @see <a href="http://tools.ietf.org/html/rfc2518#section-10.1">WebDAV</a>
|
||||
*/
|
||||
PROCESSING(102, "Processing"),
|
||||
/**
|
||||
* {@code 103 Checkpoint}.
|
||||
* @see <a href="http://code.google.com/p/gears/wiki/ResumableHttpRequestsProposal">A proposal for supporting
|
||||
* resumable POST/PUT HTTP requests in HTTP/1.0</a>
|
||||
*/
|
||||
CHECKPOINT(103, "Checkpoint"),
|
||||
|
||||
// 2xx Success
|
||||
|
||||
|
|
@ -140,6 +147,12 @@ public enum HttpStatus {
|
|||
* @see <a href="http://tools.ietf.org/html/rfc2616#section-10.3.8">HTTP/1.1</a>
|
||||
*/
|
||||
TEMPORARY_REDIRECT(307, "Temporary Redirect"),
|
||||
/**
|
||||
* {@code 308 Resume Incomplete}.
|
||||
* @see <a href="http://code.google.com/p/gears/wiki/ResumableHttpRequestsProposal">A proposal for supporting
|
||||
* resumable POST/PUT HTTP requests in HTTP/1.0</a>
|
||||
*/
|
||||
RESUME_INCOMPLETE(308, "Resume Incomplete"),
|
||||
|
||||
// --- 4xx Client Error ---
|
||||
|
||||
|
|
@ -187,7 +200,7 @@ public enum HttpStatus {
|
|||
* {@code 408 Request Timeout}.
|
||||
* @see <a href="http://tools.ietf.org/html/rfc2616#section-10.4.9">HTTP/1.1</a>
|
||||
*/
|
||||
REQUEST_TIMEOUT(408, "Request Time-out"),
|
||||
REQUEST_TIMEOUT(408, "Request Timeout"),
|
||||
/**
|
||||
* {@code 409 Conflict}.
|
||||
* @see <a href="http://tools.ietf.org/html/rfc2616#section-10.4.10">HTTP/1.1</a>
|
||||
|
|
@ -217,7 +230,7 @@ public enum HttpStatus {
|
|||
* {@code 414 Request-URI Too Long}.
|
||||
* @see <a href="http://tools.ietf.org/html/rfc2616#section-10.4.15">HTTP/1.1</a>
|
||||
*/
|
||||
REQUEST_URI_TOO_LONG(414, "Request-URI Too Large"),
|
||||
REQUEST_URI_TOO_LONG(414, "Request-URI Too Long"),
|
||||
/**
|
||||
* {@code 415 Unsupported Media Type}.
|
||||
* @see <a href="http://tools.ietf.org/html/rfc2616#section-10.4.16">HTTP/1.1</a>
|
||||
|
|
@ -233,6 +246,11 @@ public enum HttpStatus {
|
|||
* @see <a href="http://tools.ietf.org/html/rfc2616#section-10.4.18">HTTP/1.1</a>
|
||||
*/
|
||||
EXPECTATION_FAILED(417, "Expectation Failed"),
|
||||
/**
|
||||
* {@code 418 I'm a teapot}.
|
||||
* @see <a href="http://tools.ietf.org/html/rfc2324#section-2.3.2">HTCPCP/1.0</a>
|
||||
*/
|
||||
I_AM_A_TEAPOT(418, "I'm a teapot"),
|
||||
/**
|
||||
* {@code 419 Insufficient Space on Resource}.
|
||||
* @see <a href="http://tools.ietf.org/html/draft-ietf-webdav-protocol-05#section-10.4">WebDAV Draft</a>
|
||||
|
|
@ -268,6 +286,24 @@ public enum HttpStatus {
|
|||
* @see <a href="http://tools.ietf.org/html/rfc2817#section-6">Upgrading to TLS Within HTTP/1.1</a>
|
||||
*/
|
||||
UPGRADE_REQUIRED(426, "Upgrade Required"),
|
||||
/**
|
||||
* {@code 428 Precondition Required}.
|
||||
* @see <a href="http://tools.ietf.org/html/draft-nottingham-http-new-status-02#section-3">Additional HTTP Status
|
||||
* Codes</a>
|
||||
*/
|
||||
PRECONDITION_REQUIRED(428, "Precondition Required"),
|
||||
/**
|
||||
* {@code 429 Too Many Requests}.
|
||||
* @see <a href="http://tools.ietf.org/html/draft-nottingham-http-new-status-02#section-4">Additional HTTP Status
|
||||
* Codes</a>
|
||||
*/
|
||||
TOO_MANY_REQUESTS(429, "Too Many Requests"),
|
||||
/**
|
||||
* {@code 431 Request Header Fields Too Large}.
|
||||
* @see <a href="http://tools.ietf.org/html/draft-nottingham-http-new-status-02#section-5">Additional HTTP Status
|
||||
* Codes</a>
|
||||
*/
|
||||
REQUEST_HEADER_FIELDS_TOO_LARGE(431, "Request Header Fields Too Large"),
|
||||
|
||||
// --- 5xx Server Error ---
|
||||
|
||||
|
|
@ -295,7 +331,7 @@ public enum HttpStatus {
|
|||
* {@code 504 Gateway Timeout}.
|
||||
* @see <a href="http://tools.ietf.org/html/rfc2616#section-10.5.5">HTTP/1.1</a>
|
||||
*/
|
||||
GATEWAY_TIMEOUT(504, "Gateway Time-out"),
|
||||
GATEWAY_TIMEOUT(504, "Gateway Timeout"),
|
||||
/**
|
||||
* {@code 505 HTTP Version Not Supported}.
|
||||
* @see <a href="http://tools.ietf.org/html/rfc2616#section-10.5.6">HTTP/1.1</a>
|
||||
|
|
@ -316,11 +352,22 @@ public enum HttpStatus {
|
|||
* @see <a href="http://tools.ietf.org/html/draft-ietf-webdav-bind-27#section-7.2">WebDAV Binding Extensions</a>
|
||||
*/
|
||||
LOOP_DETECTED(508, "Loop Detected"),
|
||||
/**
|
||||
* {@code 509 Bandwidth Limit Exceeded}
|
||||
*/
|
||||
BANDWIDTH_LIMIT_EXCEEDED(509, "Bandwidth Limit Exceeded"),
|
||||
/**
|
||||
* {@code 510 Not Extended}
|
||||
* @see <a href="http://tools.ietf.org/html/rfc2774#section-7">HTTP Extension Framework</a>
|
||||
*/
|
||||
NOT_EXTENDED(510, "Not Extended");
|
||||
NOT_EXTENDED(510, "Not Extended"),
|
||||
/**
|
||||
* {@code 511 Network Authentication Required}.
|
||||
* @see <a href="http://tools.ietf.org/html/draft-nottingham-http-new-status-02#section-6">Additional HTTP Status
|
||||
* Codes</a>
|
||||
*/
|
||||
NETWORK_AUTHENTICATION_REQUIRED(511, "Network Authentication Required");
|
||||
|
||||
|
||||
|
||||
private final int value;
|
||||
|
|
|
|||
|
|
@ -331,7 +331,7 @@ public class MediaType implements Comparable<MediaType> {
|
|||
String attribute = entry.getKey();
|
||||
String value = entry.getValue();
|
||||
checkParameters(attribute, value);
|
||||
m.put(attribute, unquote(value));
|
||||
m.put(attribute, value);
|
||||
}
|
||||
this.parameters = Collections.unmodifiableMap(m);
|
||||
}
|
||||
|
|
@ -428,7 +428,7 @@ public class MediaType implements Comparable<MediaType> {
|
|||
*/
|
||||
public Charset getCharSet() {
|
||||
String charSet = getParameter(PARAM_CHARSET);
|
||||
return (charSet != null ? Charset.forName(charSet) : null);
|
||||
return (charSet != null ? Charset.forName(unquote(charSet)) : null);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -438,7 +438,7 @@ public class MediaType implements Comparable<MediaType> {
|
|||
*/
|
||||
public double getQualityValue() {
|
||||
String qualityFactory = getParameter(PARAM_QUALITY_FACTOR);
|
||||
return (qualityFactory != null ? Double.parseDouble(qualityFactory) : 1D);
|
||||
return (qualityFactory != null ? Double.parseDouble(unquote(qualityFactory)) : 1D);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* Copyright 2002-2012 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.http.client;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.springframework.http.HttpStatus;
|
||||
|
||||
/**
|
||||
* Abstract base for {@link ClientHttpResponse}.
|
||||
*
|
||||
* @author Arjen Poutsma
|
||||
* @since 3.1.1
|
||||
*/
|
||||
public abstract class AbstractClientHttpResponse implements ClientHttpResponse {
|
||||
|
||||
public HttpStatus getStatusCode() throws IOException {
|
||||
return HttpStatus.valueOf(getRawStatusCode());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2011 the original author or authors.
|
||||
* Copyright 2002-2012 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.
|
||||
|
|
@ -47,6 +47,10 @@ final class BufferingClientHttpResponseWrapper implements ClientHttpResponse {
|
|||
return this.response.getStatusCode();
|
||||
}
|
||||
|
||||
public int getRawStatusCode() throws IOException {
|
||||
return this.response.getRawStatusCode();
|
||||
}
|
||||
|
||||
public String getStatusText() throws IOException {
|
||||
return this.response.getStatusText();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2009 the original author or authors.
|
||||
* Copyright 2002-2012 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.
|
||||
|
|
@ -39,6 +39,13 @@ public interface ClientHttpResponse extends HttpInputMessage {
|
|||
*/
|
||||
HttpStatus getStatusCode() throws IOException;
|
||||
|
||||
/**
|
||||
* Return the HTTP status code of the response as integer
|
||||
* @return the HTTP status as an integer
|
||||
* @throws IOException in case of I/O errors
|
||||
*/
|
||||
int getRawStatusCode() throws IOException;
|
||||
|
||||
/**
|
||||
* Return the HTTP status text of the response.
|
||||
* @return the HTTP status text
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2011 the original author or authors.
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
|
@ -23,7 +23,6 @@ import org.apache.commons.httpclient.Header;
|
|||
import org.apache.commons.httpclient.HttpMethod;
|
||||
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpStatus;
|
||||
|
||||
/**
|
||||
* {@link org.springframework.http.client.ClientHttpResponse} implementation that uses
|
||||
|
|
@ -37,7 +36,7 @@ import org.springframework.http.HttpStatus;
|
|||
* @deprecated In favor of {@link HttpComponentsClientHttpResponse}
|
||||
*/
|
||||
@Deprecated
|
||||
final class CommonsClientHttpResponse implements ClientHttpResponse {
|
||||
final class CommonsClientHttpResponse extends AbstractClientHttpResponse {
|
||||
|
||||
private final HttpMethod httpMethod;
|
||||
|
||||
|
|
@ -49,8 +48,8 @@ final class CommonsClientHttpResponse implements ClientHttpResponse {
|
|||
}
|
||||
|
||||
|
||||
public HttpStatus getStatusCode() {
|
||||
return HttpStatus.valueOf(this.httpMethod.getStatusCode());
|
||||
public int getRawStatusCode() {
|
||||
return this.httpMethod.getStatusCode();
|
||||
}
|
||||
|
||||
public String getStatusText() {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2011 the original author or authors.
|
||||
* Copyright 2002-2012 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.
|
||||
|
|
@ -25,7 +25,6 @@ import org.apache.http.HttpResponse;
|
|||
import org.apache.http.util.EntityUtils;
|
||||
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpStatus;
|
||||
|
||||
/**
|
||||
* {@link org.springframework.http.client.ClientHttpResponse} implementation that uses
|
||||
|
|
@ -38,20 +37,20 @@ import org.springframework.http.HttpStatus;
|
|||
* @since 3.1
|
||||
* @see HttpComponentsClientHttpRequest#execute()
|
||||
*/
|
||||
final class HttpComponentsClientHttpResponse implements ClientHttpResponse {
|
||||
final class HttpComponentsClientHttpResponse extends AbstractClientHttpResponse {
|
||||
|
||||
private final HttpResponse httpResponse;
|
||||
|
||||
private HttpHeaders headers;
|
||||
|
||||
|
||||
public HttpComponentsClientHttpResponse(HttpResponse httpResponse) {
|
||||
HttpComponentsClientHttpResponse(HttpResponse httpResponse) {
|
||||
this.httpResponse = httpResponse;
|
||||
}
|
||||
|
||||
|
||||
public HttpStatus getStatusCode() throws IOException {
|
||||
return HttpStatus.valueOf(this.httpResponse.getStatusLine().getStatusCode());
|
||||
public int getRawStatusCode() throws IOException {
|
||||
return this.httpResponse.getStatusLine().getStatusCode();
|
||||
}
|
||||
|
||||
public String getStatusText() throws IOException {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2011 the original author or authors.
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
|
@ -21,7 +21,6 @@ import java.io.InputStream;
|
|||
import java.net.HttpURLConnection;
|
||||
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
|
|
@ -32,7 +31,7 @@ import org.springframework.util.StringUtils;
|
|||
* @author Arjen Poutsma
|
||||
* @since 3.0
|
||||
*/
|
||||
final class SimpleClientHttpResponse implements ClientHttpResponse {
|
||||
final class SimpleClientHttpResponse extends AbstractClientHttpResponse {
|
||||
|
||||
private final HttpURLConnection connection;
|
||||
|
||||
|
|
@ -44,8 +43,8 @@ final class SimpleClientHttpResponse implements ClientHttpResponse {
|
|||
}
|
||||
|
||||
|
||||
public HttpStatus getStatusCode() throws IOException {
|
||||
return HttpStatus.valueOf(this.connection.getResponseCode());
|
||||
public int getRawStatusCode() throws IOException {
|
||||
return this.connection.getResponseCode();
|
||||
}
|
||||
|
||||
public String getStatusText() throws IOException {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2010 the original author or authors.
|
||||
* Copyright 2002-2012 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.
|
||||
|
|
@ -407,7 +407,13 @@ public class JaxWsPortClientInterceptor extends LocalJaxWsServiceFactory
|
|||
*/
|
||||
protected Object getPortStub(Service service, QName portQName) {
|
||||
if (this.webServiceFeatures != null) {
|
||||
return new FeaturePortProvider().getPortStub(service, portQName, this.webServiceFeatures);
|
||||
try {
|
||||
return new FeaturePortProvider().getPortStub(service, portQName, this.webServiceFeatures);
|
||||
}
|
||||
catch (LinkageError ex) {
|
||||
throw new IllegalStateException(
|
||||
"Specifying the 'webServiceFeatures' property requires JAX-WS 2.1 or higher at runtime", ex);
|
||||
}
|
||||
}
|
||||
else {
|
||||
return (portQName != null ? service.getPort(portQName, getServiceInterface()) :
|
||||
|
|
@ -527,6 +533,7 @@ public class JaxWsPortClientInterceptor extends LocalJaxWsServiceFactory
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Inner class in order to avoid a hard-coded JAX-WS 2.1 dependency.
|
||||
* JAX-WS 2.0, as used in Java EE 5, didn't have WebServiceFeatures yet...
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2011 the original author or authors.
|
||||
* Copyright 2002-2012 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.
|
||||
|
|
@ -35,8 +35,8 @@ import org.springframework.web.method.support.HandlerMethodArgumentResolver;
|
|||
import org.springframework.web.method.support.ModelAndViewContainer;
|
||||
|
||||
/**
|
||||
* Abstract base class for resolving method arguments from a named value. Request parameters, request headers, and
|
||||
* path variables are examples of named values. Each may have a name, a required flag, and a default value.
|
||||
* Abstract base class for resolving method arguments from a named value. Request parameters, request headers, and
|
||||
* path variables are examples of named values. Each may have a name, a required flag, and a default value.
|
||||
* <p>Subclasses define how to do the following:
|
||||
* <ul>
|
||||
* <li>Obtain named value information for a method parameter
|
||||
|
|
@ -44,11 +44,11 @@ import org.springframework.web.method.support.ModelAndViewContainer;
|
|||
* <li>Handle missing argument values when argument values are required
|
||||
* <li>Optionally handle a resolved value
|
||||
* </ul>
|
||||
* <p>A default value string can contain ${...} placeholders and Spring Expression Language #{...} expressions.
|
||||
* <p>A default value string can contain ${...} placeholders and Spring Expression Language #{...} expressions.
|
||||
* For this to work a {@link ConfigurableBeanFactory} must be supplied to the class constructor.
|
||||
* <p>A {@link WebDataBinder} is created to apply type conversion to the resolved argument value if it doesn't
|
||||
* <p>A {@link WebDataBinder} is created to apply type conversion to the resolved argument value if it doesn't
|
||||
* match the method parameter type.
|
||||
*
|
||||
*
|
||||
* @author Arjen Poutsma
|
||||
* @author Rossen Stoyanchev
|
||||
* @since 3.1
|
||||
|
|
@ -63,7 +63,7 @@ public abstract class AbstractNamedValueMethodArgumentResolver implements Handle
|
|||
new ConcurrentHashMap<MethodParameter, NamedValueInfo>();
|
||||
|
||||
/**
|
||||
* @param beanFactory a bean factory to use for resolving ${...} placeholder and #{...} SpEL expressions
|
||||
* @param beanFactory a bean factory to use for resolving ${...} placeholder and #{...} SpEL expressions
|
||||
* in default values, or {@code null} if default values are not expected to contain expressions
|
||||
*/
|
||||
public AbstractNamedValueMethodArgumentResolver(ConfigurableBeanFactory beanFactory) {
|
||||
|
|
@ -71,10 +71,11 @@ public abstract class AbstractNamedValueMethodArgumentResolver implements Handle
|
|||
this.expressionContext = (beanFactory != null) ? new BeanExpressionContext(beanFactory, new RequestScope()) : null;
|
||||
}
|
||||
|
||||
public final Object resolveArgument(MethodParameter parameter,
|
||||
ModelAndViewContainer mavContainer,
|
||||
NativeWebRequest webRequest,
|
||||
WebDataBinderFactory binderFactory) throws Exception {
|
||||
public final Object resolveArgument(
|
||||
MethodParameter parameter, ModelAndViewContainer mavContainer,
|
||||
NativeWebRequest webRequest, WebDataBinderFactory binderFactory)
|
||||
throws Exception {
|
||||
|
||||
Class<?> paramType = parameter.getParameterType();
|
||||
|
||||
NamedValueInfo namedValueInfo = getNamedValueInfo(parameter);
|
||||
|
|
@ -95,7 +96,7 @@ public abstract class AbstractNamedValueMethodArgumentResolver implements Handle
|
|||
WebDataBinder binder = binderFactory.createBinder(webRequest, null, namedValueInfo.name);
|
||||
arg = binder.convertIfNecessary(arg, paramType, parameter);
|
||||
}
|
||||
|
||||
|
||||
handleResolvedValue(arg, namedValueInfo.name, parameter, mavContainer, webRequest);
|
||||
|
||||
return arg;
|
||||
|
|
@ -115,9 +116,9 @@ public abstract class AbstractNamedValueMethodArgumentResolver implements Handle
|
|||
}
|
||||
|
||||
/**
|
||||
* Create the {@link NamedValueInfo} object for the given method parameter. Implementations typically
|
||||
* Create the {@link NamedValueInfo} object for the given method parameter. Implementations typically
|
||||
* retrieve the method annotation by means of {@link MethodParameter#getParameterAnnotation(Class)}.
|
||||
*
|
||||
*
|
||||
* @param parameter the method parameter
|
||||
* @return the named value information
|
||||
*/
|
||||
|
|
@ -136,7 +137,7 @@ public abstract class AbstractNamedValueMethodArgumentResolver implements Handle
|
|||
String defaultValue = (ValueConstants.DEFAULT_NONE.equals(info.defaultValue) ? null : info.defaultValue);
|
||||
return new NamedValueInfo(name, info.required, defaultValue);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Resolves the given parameter type and value name into an argument value.
|
||||
* @param name the name of the value being resolved
|
||||
|
|
@ -165,7 +166,7 @@ public abstract class AbstractNamedValueMethodArgumentResolver implements Handle
|
|||
}
|
||||
|
||||
/**
|
||||
* Invoked when a named value is required, but {@link #resolveName(String, MethodParameter, NativeWebRequest)}
|
||||
* Invoked when a named value is required, but {@link #resolveName(String, MethodParameter, NativeWebRequest)}
|
||||
* returned {@code null} and there is no default value. Subclasses typically throw an exception in this case.
|
||||
* @param name the name for the value
|
||||
* @param parameter the method parameter
|
||||
|
|
@ -219,4 +220,4 @@ public abstract class AbstractNamedValueMethodArgumentResolver implements Handle
|
|||
this.defaultValue = defaultValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2011 the original author or authors.
|
||||
* Copyright 2002-2012 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.
|
||||
|
|
@ -28,16 +28,16 @@ import org.springframework.web.method.support.HandlerMethodArgumentResolver;
|
|||
import org.springframework.web.method.support.ModelAndViewContainer;
|
||||
|
||||
/**
|
||||
* An abstract base class adapting a {@link WebArgumentResolver} to the
|
||||
* {@link HandlerMethodArgumentResolver} contract.
|
||||
*
|
||||
* An abstract base class adapting a {@link WebArgumentResolver} to the
|
||||
* {@link HandlerMethodArgumentResolver} contract.
|
||||
*
|
||||
* <p><strong>Note:</strong> This class is provided for backwards compatibility.
|
||||
* However it is recommended to re-write a {@code WebArgumentResolver} as
|
||||
* {@code HandlerMethodArgumentResolver}. Since {@link #supportsParameter}
|
||||
* can only be implemented by actually resolving the value and then checking
|
||||
* the result is not {@code WebArgumentResolver#UNRESOLVED} any exceptions
|
||||
* raised must be absorbed and ignored since it's not clear whether the adapter
|
||||
* doesn't support the parameter or whether it failed for an internal reason.
|
||||
* However it is recommended to re-write a {@code WebArgumentResolver} as
|
||||
* {@code HandlerMethodArgumentResolver}. Since {@link #supportsParameter}
|
||||
* can only be implemented by actually resolving the value and then checking
|
||||
* the result is not {@code WebArgumentResolver#UNRESOLVED} any exceptions
|
||||
* raised must be absorbed and ignored since it's not clear whether the adapter
|
||||
* doesn't support the parameter or whether it failed for an internal reason.
|
||||
* The {@code HandlerMethodArgumentResolver} contract also provides access to
|
||||
* model attributes and to {@code WebDataBinderFactory} (for type conversion).
|
||||
*
|
||||
|
|
@ -60,7 +60,7 @@ public abstract class AbstractWebArgumentResolverAdapter implements HandlerMetho
|
|||
}
|
||||
|
||||
/**
|
||||
* Actually resolve the value and check the resolved value is not
|
||||
* Actually resolve the value and check the resolved value is not
|
||||
* {@link WebArgumentResolver#UNRESOLVED} absorbing _any_ exceptions.
|
||||
*/
|
||||
public boolean supportsParameter(MethodParameter parameter) {
|
||||
|
|
@ -88,21 +88,22 @@ public abstract class AbstractWebArgumentResolverAdapter implements HandlerMetho
|
|||
|
||||
/**
|
||||
* Delegate to the {@link WebArgumentResolver} instance.
|
||||
* @exception IllegalStateException if the resolved value is not assignable
|
||||
* @exception IllegalStateException if the resolved value is not assignable
|
||||
* to the method parameter.
|
||||
*/
|
||||
public Object resolveArgument(MethodParameter parameter,
|
||||
ModelAndViewContainer mavContainer,
|
||||
NativeWebRequest webRequest,
|
||||
WebDataBinderFactory binderFactory) throws Exception {
|
||||
public Object resolveArgument(
|
||||
MethodParameter parameter, ModelAndViewContainer mavContainer,
|
||||
NativeWebRequest webRequest, WebDataBinderFactory binderFactory)
|
||||
throws Exception {
|
||||
|
||||
Class<?> paramType = parameter.getParameterType();
|
||||
Object result = this.adaptee.resolveArgument(parameter, webRequest);
|
||||
if (result == WebArgumentResolver.UNRESOLVED || !ClassUtils.isAssignableValue(paramType, result)) {
|
||||
throw new IllegalStateException(
|
||||
"Standard argument type [" + paramType.getName() + "] in method " + parameter.getMethod() +
|
||||
"Standard argument type [" + paramType.getName() + "] in method " + parameter.getMethod() +
|
||||
"resolved to incompatible value of type [" + (result != null ? result.getClass() : null) +
|
||||
"]. Consider declaring the argument type in a less specific fashion.");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2011 the original author or authors.
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
|
@ -29,12 +29,12 @@ import org.springframework.web.method.support.ModelAndViewContainer;
|
|||
|
||||
/**
|
||||
* Resolves {@link Errors} method arguments.
|
||||
*
|
||||
*
|
||||
* <p>An {@code Errors} method argument is expected to appear immediately after
|
||||
* the model attribute in the method signature. It is resolved by expecting the
|
||||
* last two attributes added to the model to be the model attribute and its
|
||||
* {@link BindingResult}.
|
||||
*
|
||||
* {@link BindingResult}.
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
* @since 3.1
|
||||
*/
|
||||
|
|
@ -45,10 +45,11 @@ public class ErrorsMethodArgumentResolver implements HandlerMethodArgumentResolv
|
|||
return Errors.class.isAssignableFrom(paramType);
|
||||
}
|
||||
|
||||
public Object resolveArgument(MethodParameter parameter,
|
||||
ModelAndViewContainer mavContainer,
|
||||
NativeWebRequest webRequest,
|
||||
WebDataBinderFactory binderFactory) throws Exception {
|
||||
public Object resolveArgument(
|
||||
MethodParameter parameter, ModelAndViewContainer mavContainer,
|
||||
NativeWebRequest webRequest, WebDataBinderFactory binderFactory)
|
||||
throws Exception {
|
||||
|
||||
ModelMap model = mavContainer.getModel();
|
||||
if (model.size() > 0) {
|
||||
int lastIndex = model.size()-1;
|
||||
|
|
@ -63,4 +64,4 @@ public class ErrorsMethodArgumentResolver implements HandlerMethodArgumentResolv
|
|||
"argument in the controller method signature: " + parameter.getMethod());
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2011 the original author or authors.
|
||||
* Copyright 2002-2012 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.
|
||||
|
|
@ -27,12 +27,12 @@ import org.springframework.web.method.support.ModelAndViewContainer;
|
|||
|
||||
/**
|
||||
* Resolves {@link Map} method arguments and handles {@link Map} return values.
|
||||
*
|
||||
* <p>A Map return value can be interpreted in more than one ways depending
|
||||
* on the presence of annotations like {@code @ModelAttribute} or
|
||||
*
|
||||
* <p>A Map return value can be interpreted in more than one ways depending
|
||||
* on the presence of annotations like {@code @ModelAttribute} or
|
||||
* {@code @ResponseBody}. Therefore this handler should be configured after
|
||||
* the handlers that support these annotations.
|
||||
*
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
* @since 3.1
|
||||
*/
|
||||
|
|
@ -42,10 +42,11 @@ public class MapMethodProcessor implements HandlerMethodArgumentResolver, Handle
|
|||
return Map.class.isAssignableFrom(parameter.getParameterType());
|
||||
}
|
||||
|
||||
public Object resolveArgument(MethodParameter parameter,
|
||||
ModelAndViewContainer mavContainer,
|
||||
NativeWebRequest webRequest,
|
||||
WebDataBinderFactory binderFactory) throws Exception {
|
||||
public Object resolveArgument(
|
||||
MethodParameter parameter, ModelAndViewContainer mavContainer,
|
||||
NativeWebRequest webRequest, WebDataBinderFactory binderFactory)
|
||||
throws Exception {
|
||||
|
||||
return mavContainer.getModel();
|
||||
}
|
||||
|
||||
|
|
@ -54,10 +55,11 @@ public class MapMethodProcessor implements HandlerMethodArgumentResolver, Handle
|
|||
}
|
||||
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
public void handleReturnValue(Object returnValue,
|
||||
MethodParameter returnType,
|
||||
ModelAndViewContainer mavContainer,
|
||||
NativeWebRequest webRequest) throws Exception {
|
||||
public void handleReturnValue(
|
||||
Object returnValue, MethodParameter returnType,
|
||||
ModelAndViewContainer mavContainer, NativeWebRequest webRequest)
|
||||
throws Exception {
|
||||
|
||||
if (returnValue == null) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -66,8 +68,8 @@ public class MapMethodProcessor implements HandlerMethodArgumentResolver, Handle
|
|||
}
|
||||
else {
|
||||
// should not happen
|
||||
throw new UnsupportedOperationException("Unexpected return type: " +
|
||||
throw new UnsupportedOperationException("Unexpected return type: " +
|
||||
returnType.getParameterType().getName() + " in method: " + returnType.getMethod());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2011 the original author or authors.
|
||||
* Copyright 2002-2012 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.
|
||||
|
|
@ -39,15 +39,15 @@ import org.springframework.web.method.support.ModelAndViewContainer;
|
|||
/**
|
||||
* Resolves method arguments annotated with {@code @ModelAttribute} and handles
|
||||
* return values from methods annotated with {@code @ModelAttribute}.
|
||||
*
|
||||
* <p>Model attributes are obtained from the model or if not found possibly
|
||||
* created with a default constructor if it is available. Once created, the
|
||||
* attributed is populated with request data via data binding and also
|
||||
* validation may be applied if the argument is annotated with
|
||||
*
|
||||
* <p>Model attributes are obtained from the model or if not found possibly
|
||||
* created with a default constructor if it is available. Once created, the
|
||||
* attributed is populated with request data via data binding and also
|
||||
* validation may be applied if the argument is annotated with
|
||||
* {@code @javax.validation.Valid}.
|
||||
*
|
||||
* <p>When this handler is created with {@code annotationNotRequired=true},
|
||||
* any non-simple type argument and return value is regarded as a model
|
||||
* <p>When this handler is created with {@code annotationNotRequired=true},
|
||||
* any non-simple type argument and return value is regarded as a model
|
||||
* attribute with or without the presence of an {@code @ModelAttribute}.
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
|
|
@ -58,10 +58,10 @@ public class ModelAttributeMethodProcessor implements HandlerMethodArgumentResol
|
|||
protected Log logger = LogFactory.getLog(this.getClass());
|
||||
|
||||
private final boolean annotationNotRequired;
|
||||
|
||||
|
||||
/**
|
||||
* @param annotationNotRequired if "true", non-simple method arguments and
|
||||
* return values are considered model attributes with or without a
|
||||
* return values are considered model attributes with or without a
|
||||
* {@code @ModelAttribute} annotation.
|
||||
*/
|
||||
public ModelAttributeMethodProcessor(boolean annotationNotRequired) {
|
||||
|
|
@ -85,18 +85,19 @@ public class ModelAttributeMethodProcessor implements HandlerMethodArgumentResol
|
|||
}
|
||||
|
||||
/**
|
||||
* Resolve the argument from the model or if not found instantiate it with
|
||||
* its default if it is available. The model attribute is then populated
|
||||
* Resolve the argument from the model or if not found instantiate it with
|
||||
* its default if it is available. The model attribute is then populated
|
||||
* with request values via data binding and optionally validated
|
||||
* if {@code @java.validation.Valid} is present on the argument.
|
||||
* @throws BindException if data binding and validation result in an error
|
||||
* and the next method parameter is not of type {@link Errors}.
|
||||
* @throws Exception if WebDataBinder initialization fails.
|
||||
*/
|
||||
public final Object resolveArgument(MethodParameter parameter,
|
||||
ModelAndViewContainer mavContainer,
|
||||
NativeWebRequest request,
|
||||
WebDataBinderFactory binderFactory) throws Exception {
|
||||
public final Object resolveArgument(
|
||||
MethodParameter parameter, ModelAndViewContainer mavContainer,
|
||||
NativeWebRequest request, WebDataBinderFactory binderFactory)
|
||||
throws Exception {
|
||||
|
||||
String name = ModelFactory.getNameForParameter(parameter);
|
||||
Object target = (mavContainer.containsAttribute(name)) ?
|
||||
mavContainer.getModel().get(name) : createAttribute(name, parameter, binderFactory, request);
|
||||
|
|
@ -130,7 +131,7 @@ public class ModelAttributeMethodProcessor implements HandlerMethodArgumentResol
|
|||
|
||||
return BeanUtils.instantiateClass(parameter.getParameterType());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Extension point to bind the request to the target object.
|
||||
* @param binder the data binder instance to use for the binding
|
||||
|
|
@ -158,7 +159,7 @@ public class ModelAttributeMethodProcessor implements HandlerMethodArgumentResol
|
|||
|
||||
/**
|
||||
* Whether to raise a {@link BindException} on bind or validation errors.
|
||||
* The default implementation returns {@code true} if the next method
|
||||
* The default implementation returns {@code true} if the next method
|
||||
* argument is not of type {@link Errors}.
|
||||
* @param binder the data binder used to perform data binding
|
||||
* @param parameter the method argument
|
||||
|
|
@ -167,12 +168,12 @@ public class ModelAttributeMethodProcessor implements HandlerMethodArgumentResol
|
|||
int i = parameter.getParameterIndex();
|
||||
Class<?>[] paramTypes = parameter.getMethod().getParameterTypes();
|
||||
boolean hasBindingResult = (paramTypes.length > (i + 1) && Errors.class.isAssignableFrom(paramTypes[i + 1]));
|
||||
|
||||
|
||||
return !hasBindingResult;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return {@code true} if there is a method-level {@code @ModelAttribute}
|
||||
* Return {@code true} if there is a method-level {@code @ModelAttribute}
|
||||
* or if it is a non-simple type when {@code annotationNotRequired=true}.
|
||||
*/
|
||||
public boolean supportsReturnType(MethodParameter returnType) {
|
||||
|
|
@ -190,13 +191,14 @@ public class ModelAttributeMethodProcessor implements HandlerMethodArgumentResol
|
|||
/**
|
||||
* Add non-null return values to the {@link ModelAndViewContainer}.
|
||||
*/
|
||||
public void handleReturnValue(Object returnValue,
|
||||
MethodParameter returnType,
|
||||
ModelAndViewContainer mavContainer,
|
||||
NativeWebRequest webRequest) throws Exception {
|
||||
public void handleReturnValue(
|
||||
Object returnValue, MethodParameter returnType,
|
||||
ModelAndViewContainer mavContainer, NativeWebRequest webRequest)
|
||||
throws Exception {
|
||||
|
||||
if (returnValue != null) {
|
||||
String name = ModelFactory.getNameForReturnValue(returnValue, returnType);
|
||||
mavContainer.addAttribute(name, returnValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2011 the original author or authors.
|
||||
* Copyright 2002-2012 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.
|
||||
|
|
@ -25,13 +25,13 @@ import org.springframework.web.method.support.HandlerMethodReturnValueHandler;
|
|||
import org.springframework.web.method.support.ModelAndViewContainer;
|
||||
|
||||
/**
|
||||
* Resolves {@link Model} arguments and handles {@link Model} return values.
|
||||
*
|
||||
* <p>A {@link Model} return type has a set purpose. Therefore this handler
|
||||
* should be configured ahead of handlers that support any return value type
|
||||
* Resolves {@link Model} arguments and handles {@link Model} return values.
|
||||
*
|
||||
* <p>A {@link Model} return type has a set purpose. Therefore this handler
|
||||
* should be configured ahead of handlers that support any return value type
|
||||
* annotated with {@code @ModelAttribute} or {@code @ResponseBody} to ensure
|
||||
* they don't take over.
|
||||
*
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
* @since 3.1
|
||||
*/
|
||||
|
|
@ -41,10 +41,11 @@ public class ModelMethodProcessor implements HandlerMethodArgumentResolver, Hand
|
|||
return Model.class.isAssignableFrom(parameter.getParameterType());
|
||||
}
|
||||
|
||||
public Object resolveArgument(MethodParameter parameter,
|
||||
ModelAndViewContainer mavContainer,
|
||||
NativeWebRequest webRequest,
|
||||
WebDataBinderFactory binderFactory) throws Exception {
|
||||
public Object resolveArgument(
|
||||
MethodParameter parameter, ModelAndViewContainer mavContainer,
|
||||
NativeWebRequest webRequest, WebDataBinderFactory binderFactory)
|
||||
throws Exception {
|
||||
|
||||
return mavContainer.getModel();
|
||||
}
|
||||
|
||||
|
|
@ -52,10 +53,11 @@ public class ModelMethodProcessor implements HandlerMethodArgumentResolver, Hand
|
|||
return Model.class.isAssignableFrom(returnType.getParameterType());
|
||||
}
|
||||
|
||||
public void handleReturnValue(Object returnValue,
|
||||
MethodParameter returnType,
|
||||
ModelAndViewContainer mavContainer,
|
||||
NativeWebRequest webRequest) throws Exception {
|
||||
public void handleReturnValue(
|
||||
Object returnValue, MethodParameter returnType,
|
||||
ModelAndViewContainer mavContainer, NativeWebRequest webRequest)
|
||||
throws Exception {
|
||||
|
||||
if (returnValue == null) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -64,8 +66,8 @@ public class ModelMethodProcessor implements HandlerMethodArgumentResolver, Hand
|
|||
}
|
||||
else {
|
||||
// should not happen
|
||||
throw new UnsupportedOperationException("Unexpected return type: " +
|
||||
throw new UnsupportedOperationException("Unexpected return type: " +
|
||||
returnType.getParameterType().getName() + " in method: " + returnType.getMethod());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2011 the original author or authors.
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
|
@ -31,13 +31,13 @@ import org.springframework.web.method.support.HandlerMethodArgumentResolver;
|
|||
import org.springframework.web.method.support.ModelAndViewContainer;
|
||||
|
||||
/**
|
||||
* Resolves {@link Map} method arguments annotated with {@code @RequestHeader}.
|
||||
* For individual header values annotated with {@code @RequestHeader} see
|
||||
* Resolves {@link Map} method arguments annotated with {@code @RequestHeader}.
|
||||
* For individual header values annotated with {@code @RequestHeader} see
|
||||
* {@link RequestHeaderMethodArgumentResolver} instead.
|
||||
*
|
||||
* <p>The created {@link Map} contains all request header name/value pairs.
|
||||
*
|
||||
* <p>The created {@link Map} contains all request header name/value pairs.
|
||||
* The method parameter type may be a {@link MultiValueMap} to receive all
|
||||
* values for a header, not only the first one.
|
||||
* values for a header, not only the first one.
|
||||
*
|
||||
* @author Arjen Poutsma
|
||||
* @author Rossen Stoyanchev
|
||||
|
|
@ -50,10 +50,11 @@ public class RequestHeaderMapMethodArgumentResolver implements HandlerMethodArgu
|
|||
&& Map.class.isAssignableFrom(parameter.getParameterType());
|
||||
}
|
||||
|
||||
public Object resolveArgument(MethodParameter parameter,
|
||||
ModelAndViewContainer mavContainer,
|
||||
NativeWebRequest webRequest,
|
||||
WebDataBinderFactory binderFactory) throws Exception {
|
||||
public Object resolveArgument(
|
||||
MethodParameter parameter, ModelAndViewContainer mavContainer,
|
||||
NativeWebRequest webRequest, WebDataBinderFactory binderFactory)
|
||||
throws Exception {
|
||||
|
||||
Class<?> paramType = parameter.getParameterType();
|
||||
|
||||
if (MultiValueMap.class.isAssignableFrom(paramType)) {
|
||||
|
|
@ -82,4 +83,4 @@ public class RequestHeaderMapMethodArgumentResolver implements HandlerMethodArgu
|
|||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2011 the original author or authors.
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
|
@ -30,12 +30,12 @@ import org.springframework.web.method.support.HandlerMethodArgumentResolver;
|
|||
import org.springframework.web.method.support.ModelAndViewContainer;
|
||||
|
||||
/**
|
||||
* Resolves {@link Map} method arguments annotated with an @{@link RequestParam} where the annotation does not
|
||||
* specify a request parameter name. See {@link RequestParamMethodArgumentResolver} for resolving {@link Map}
|
||||
* Resolves {@link Map} method arguments annotated with an @{@link RequestParam} where the annotation does not
|
||||
* specify a request parameter name. See {@link RequestParamMethodArgumentResolver} for resolving {@link Map}
|
||||
* method arguments with a request parameter name.
|
||||
*
|
||||
* <p>The created {@link Map} contains all request parameter name/value pairs. If the method parameter type
|
||||
* is {@link MultiValueMap} instead, the created map contains all request parameters and all there values for
|
||||
*
|
||||
* <p>The created {@link Map} contains all request parameter name/value pairs. If the method parameter type
|
||||
* is {@link MultiValueMap} instead, the created map contains all request parameters and all there values for
|
||||
* cases where request parameters have multiple values.
|
||||
*
|
||||
* @author Arjen Poutsma
|
||||
|
|
@ -55,10 +55,11 @@ public class RequestParamMapMethodArgumentResolver implements HandlerMethodArgum
|
|||
return false;
|
||||
}
|
||||
|
||||
public Object resolveArgument(MethodParameter parameter,
|
||||
ModelAndViewContainer mavContainer,
|
||||
NativeWebRequest webRequest,
|
||||
WebDataBinderFactory binderFactory) throws Exception {
|
||||
public Object resolveArgument(
|
||||
MethodParameter parameter, ModelAndViewContainer mavContainer,
|
||||
NativeWebRequest webRequest, WebDataBinderFactory binderFactory)
|
||||
throws Exception {
|
||||
|
||||
Class<?> paramType = parameter.getParameterType();
|
||||
|
||||
Map<String, String[]> parameterMap = webRequest.getParameterMap();
|
||||
|
|
@ -81,4 +82,4 @@ public class RequestParamMapMethodArgumentResolver implements HandlerMethodArgum
|
|||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2011 the original author or authors.
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
|
@ -24,7 +24,7 @@ import org.springframework.web.method.support.HandlerMethodArgumentResolver;
|
|||
import org.springframework.web.method.support.ModelAndViewContainer;
|
||||
|
||||
/**
|
||||
* Resolves a {@link SessionStatus} argument by obtaining it from
|
||||
* Resolves a {@link SessionStatus} argument by obtaining it from
|
||||
* the {@link ModelAndViewContainer}.
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
|
|
@ -36,10 +36,11 @@ public class SessionStatusMethodArgumentResolver implements HandlerMethodArgumen
|
|||
return SessionStatus.class.equals(parameter.getParameterType());
|
||||
}
|
||||
|
||||
public Object resolveArgument(MethodParameter parameter,
|
||||
ModelAndViewContainer mavContainer,
|
||||
NativeWebRequest webRequest,
|
||||
WebDataBinderFactory binderFactory) throws Exception {
|
||||
public Object resolveArgument(
|
||||
MethodParameter parameter, ModelAndViewContainer mavContainer,
|
||||
NativeWebRequest webRequest, WebDataBinderFactory binderFactory)
|
||||
throws Exception {
|
||||
|
||||
return mavContainer.getSessionStatus();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2011 the original author or authors.
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
|
@ -31,8 +31,8 @@ import org.springframework.web.context.request.NativeWebRequest;
|
|||
|
||||
/**
|
||||
* Resolves method parameters by delegating to a list of registered {@link HandlerMethodArgumentResolver}s.
|
||||
* Previously resolved method parameters are cached for faster lookups.
|
||||
*
|
||||
* Previously resolved method parameters are cached for faster lookups.
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
* @since 3.1
|
||||
*/
|
||||
|
|
@ -40,12 +40,12 @@ public class HandlerMethodArgumentResolverComposite implements HandlerMethodArgu
|
|||
|
||||
protected final Log logger = LogFactory.getLog(getClass());
|
||||
|
||||
private final List<HandlerMethodArgumentResolver> argumentResolvers =
|
||||
private final List<HandlerMethodArgumentResolver> argumentResolvers =
|
||||
new ArrayList<HandlerMethodArgumentResolver>();
|
||||
|
||||
private final Map<MethodParameter, HandlerMethodArgumentResolver> argumentResolverCache =
|
||||
new ConcurrentHashMap<MethodParameter, HandlerMethodArgumentResolver>();
|
||||
|
||||
|
||||
/**
|
||||
* Return a read-only list with the contained resolvers, or an empty list.
|
||||
*/
|
||||
|
|
@ -54,7 +54,7 @@ public class HandlerMethodArgumentResolverComposite implements HandlerMethodArgu
|
|||
}
|
||||
|
||||
/**
|
||||
* Whether the given {@linkplain MethodParameter method parameter} is supported by any registered
|
||||
* Whether the given {@linkplain MethodParameter method parameter} is supported by any registered
|
||||
* {@link HandlerMethodArgumentResolver}.
|
||||
*/
|
||||
public boolean supportsParameter(MethodParameter parameter) {
|
||||
|
|
@ -65,10 +65,11 @@ public class HandlerMethodArgumentResolverComposite implements HandlerMethodArgu
|
|||
* Iterate over registered {@link HandlerMethodArgumentResolver}s and invoke the one that supports it.
|
||||
* @exception IllegalStateException if no suitable {@link HandlerMethodArgumentResolver} is found.
|
||||
*/
|
||||
public Object resolveArgument(MethodParameter parameter,
|
||||
ModelAndViewContainer mavContainer,
|
||||
NativeWebRequest webRequest,
|
||||
WebDataBinderFactory binderFactory) throws Exception {
|
||||
public Object resolveArgument(
|
||||
MethodParameter parameter, ModelAndViewContainer mavContainer,
|
||||
NativeWebRequest webRequest, WebDataBinderFactory binderFactory)
|
||||
throws Exception {
|
||||
|
||||
HandlerMethodArgumentResolver resolver = getArgumentResolver(parameter);
|
||||
Assert.notNull(resolver, "Unknown parameter type [" + parameter.getParameterType().getName() + "]");
|
||||
return resolver.resolveArgument(parameter, mavContainer, webRequest, binderFactory);
|
||||
|
|
@ -94,7 +95,7 @@ public class HandlerMethodArgumentResolverComposite implements HandlerMethodArgu
|
|||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Add the given {@link HandlerMethodArgumentResolver}.
|
||||
*/
|
||||
|
|
@ -116,4 +117,4 @@ public class HandlerMethodArgumentResolverComposite implements HandlerMethodArgu
|
|||
return this;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2011 the original author or authors.
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
|
@ -29,17 +29,17 @@ import org.springframework.util.Assert;
|
|||
import org.springframework.web.context.request.NativeWebRequest;
|
||||
|
||||
/**
|
||||
* Handles method return values by delegating to a list of registered {@link HandlerMethodReturnValueHandler}s.
|
||||
* Previously resolved return types are cached for faster lookups.
|
||||
*
|
||||
* Handles method return values by delegating to a list of registered {@link HandlerMethodReturnValueHandler}s.
|
||||
* Previously resolved return types are cached for faster lookups.
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
* @since 3.1
|
||||
*/
|
||||
public class HandlerMethodReturnValueHandlerComposite implements HandlerMethodReturnValueHandler {
|
||||
|
||||
|
||||
protected final Log logger = LogFactory.getLog(getClass());
|
||||
|
||||
private final List<HandlerMethodReturnValueHandler> returnValueHandlers =
|
||||
private final List<HandlerMethodReturnValueHandler> returnValueHandlers =
|
||||
new ArrayList<HandlerMethodReturnValueHandler>();
|
||||
|
||||
private final Map<MethodParameter, HandlerMethodReturnValueHandler> returnValueHandlerCache =
|
||||
|
|
@ -53,7 +53,7 @@ public class HandlerMethodReturnValueHandlerComposite implements HandlerMethodRe
|
|||
}
|
||||
|
||||
/**
|
||||
* Whether the given {@linkplain MethodParameter method return type} is supported by any registered
|
||||
* Whether the given {@linkplain MethodParameter method return type} is supported by any registered
|
||||
* {@link HandlerMethodReturnValueHandler}.
|
||||
*/
|
||||
public boolean supportsReturnType(MethodParameter returnType) {
|
||||
|
|
@ -64,10 +64,11 @@ public class HandlerMethodReturnValueHandlerComposite implements HandlerMethodRe
|
|||
* Iterate over registered {@link HandlerMethodReturnValueHandler}s and invoke the one that supports it.
|
||||
* @exception IllegalStateException if no suitable {@link HandlerMethodReturnValueHandler} is found.
|
||||
*/
|
||||
public void handleReturnValue(Object returnValue,
|
||||
MethodParameter returnType,
|
||||
ModelAndViewContainer mavContainer,
|
||||
NativeWebRequest webRequest) throws Exception {
|
||||
public void handleReturnValue(
|
||||
Object returnValue, MethodParameter returnType,
|
||||
ModelAndViewContainer mavContainer, NativeWebRequest webRequest)
|
||||
throws Exception {
|
||||
|
||||
HandlerMethodReturnValueHandler handler = getReturnValueHandler(returnType);
|
||||
Assert.notNull(handler, "Unknown return value type [" + returnType.getParameterType().getName() + "]");
|
||||
handler.handleReturnValue(returnValue, returnType, mavContainer, webRequest);
|
||||
|
|
@ -92,8 +93,8 @@ public class HandlerMethodReturnValueHandlerComposite implements HandlerMethodRe
|
|||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the given {@link HandlerMethodReturnValueHandler}.
|
||||
*/
|
||||
|
|
@ -115,4 +116,4 @@ public class HandlerMethodReturnValueHandlerComposite implements HandlerMethodRe
|
|||
return this;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2011 the original author or authors.
|
||||
* Copyright 2002-2012 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.
|
||||
|
|
@ -32,16 +32,16 @@ import org.springframework.web.context.request.NativeWebRequest;
|
|||
import org.springframework.web.method.HandlerMethod;
|
||||
|
||||
/**
|
||||
* Provides a method for invoking the handler method for a given request after resolving its method argument
|
||||
* Provides a method for invoking the handler method for a given request after resolving its method argument
|
||||
* values through registered {@link HandlerMethodArgumentResolver}s.
|
||||
*
|
||||
* <p>Argument resolution often requires a {@link WebDataBinder} for data binding or for type conversion.
|
||||
*
|
||||
* <p>Argument resolution often requires a {@link WebDataBinder} for data binding or for type conversion.
|
||||
* Use the {@link #setDataBinderFactory(WebDataBinderFactory)} property to supply a binder factory to pass to
|
||||
* argument resolvers.
|
||||
*
|
||||
* <p>Use {@link #setHandlerMethodArgumentResolvers(HandlerMethodArgumentResolverComposite)} to customize
|
||||
* argument resolvers.
|
||||
*
|
||||
* <p>Use {@link #setHandlerMethodArgumentResolvers(HandlerMethodArgumentResolverComposite)} to customize
|
||||
* the list of argument resolvers.
|
||||
*
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
* @since 3.1
|
||||
*/
|
||||
|
|
@ -99,20 +99,20 @@ public class InvocableHandlerMethod extends HandlerMethod {
|
|||
}
|
||||
|
||||
/**
|
||||
* Invoke the method after resolving its argument values in the context of the given request. <p>Argument
|
||||
* values are commonly resolved through {@link HandlerMethodArgumentResolver}s. The {@code provideArgs}
|
||||
* parameter however may supply argument values to be used directly, i.e. without argument resolution.
|
||||
* Examples of provided argument values include a {@link WebDataBinder}, a {@link SessionStatus}, or
|
||||
* Invoke the method after resolving its argument values in the context of the given request. <p>Argument
|
||||
* values are commonly resolved through {@link HandlerMethodArgumentResolver}s. The {@code provideArgs}
|
||||
* parameter however may supply argument values to be used directly, i.e. without argument resolution.
|
||||
* Examples of provided argument values include a {@link WebDataBinder}, a {@link SessionStatus}, or
|
||||
* a thrown exception instance. Provided argument values are checked before argument resolvers.
|
||||
*
|
||||
*
|
||||
* @param request the current request
|
||||
* @param mavContainer the {@link ModelAndViewContainer} for the current request
|
||||
* @param providedArgs argument values to try to use without view resolution
|
||||
* @return the raw value returned by the invoked method
|
||||
* @exception Exception raised if no suitable argument resolver can be found, or the method raised an exception
|
||||
* @exception Exception raised if no suitable argument resolver can be found, or the method raised an exception
|
||||
*/
|
||||
public final Object invokeForRequest(NativeWebRequest request,
|
||||
ModelAndViewContainer mavContainer,
|
||||
public final Object invokeForRequest(NativeWebRequest request,
|
||||
ModelAndViewContainer mavContainer,
|
||||
Object... providedArgs) throws Exception {
|
||||
Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);
|
||||
|
||||
|
|
@ -135,9 +135,10 @@ public class InvocableHandlerMethod extends HandlerMethod {
|
|||
/**
|
||||
* Get the method argument values for the current request.
|
||||
*/
|
||||
private Object[] getMethodArgumentValues(NativeWebRequest request,
|
||||
ModelAndViewContainer mavContainer,
|
||||
Object... providedArgs) throws Exception {
|
||||
private Object[] getMethodArgumentValues(
|
||||
NativeWebRequest request, ModelAndViewContainer mavContainer,
|
||||
Object... providedArgs) throws Exception {
|
||||
|
||||
MethodParameter[] parameters = getMethodParameters();
|
||||
Object[] args = new Object[parameters.length];
|
||||
for (int i = 0; i < parameters.length; i++) {
|
||||
|
|
@ -187,7 +188,7 @@ public class InvocableHandlerMethod extends HandlerMethod {
|
|||
sb.append("Method [").append(getBridgedMethod().toGenericString()).append("]\n");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Attempt to resolve a method parameter from the list of provided argument values.
|
||||
*/
|
||||
|
|
@ -202,7 +203,7 @@ public class InvocableHandlerMethod extends HandlerMethod {
|
|||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Invoke the handler method with the given argument values.
|
||||
*/
|
||||
|
|
@ -215,7 +216,7 @@ public class InvocableHandlerMethod extends HandlerMethod {
|
|||
String msg = getInvocationErrorMessage(e.getMessage(), args);
|
||||
throw new IllegalArgumentException(msg, e);
|
||||
}
|
||||
catch (InvocationTargetException e) {
|
||||
catch (InvocationTargetException e) {
|
||||
// Unwrap for HandlerExceptionResolvers ...
|
||||
Throwable targetException = e.getTargetException();
|
||||
if (targetException instanceof RuntimeException) {
|
||||
|
|
@ -233,7 +234,7 @@ public class InvocableHandlerMethod extends HandlerMethod {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private String getInvocationErrorMessage(String message, Object[] resolvedArgs) {
|
||||
StringBuilder sb = new StringBuilder(getDetailedErrorMessage(message));
|
||||
sb.append("Resolved arguments: \n");
|
||||
|
|
@ -250,4 +251,4 @@ public class InvocableHandlerMethod extends HandlerMethod {
|
|||
return sb.toString();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,6 +18,8 @@ package org.springframework.web.util;
|
|||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
|
|
@ -38,38 +40,107 @@ import org.springframework.util.Assert;
|
|||
*/
|
||||
public abstract class UriUtils {
|
||||
|
||||
private static final String SCHEME_PATTERN = "([^:/?#]+):";
|
||||
|
||||
private static final String HTTP_PATTERN = "(http|https):";
|
||||
|
||||
private static final String USERINFO_PATTERN = "([^@/]*)";
|
||||
|
||||
private static final String HOST_PATTERN = "([^/?#:]*)";
|
||||
|
||||
private static final String PORT_PATTERN = "(\\d*)";
|
||||
|
||||
private static final String PATH_PATTERN = "([^?#]*)";
|
||||
|
||||
private static final String QUERY_PATTERN = "([^#]*)";
|
||||
|
||||
private static final String LAST_PATTERN = "(.*)";
|
||||
|
||||
// Regex patterns that matches URIs. See RFC 3986, appendix B
|
||||
private static final Pattern URI_PATTERN = Pattern.compile(
|
||||
"^(" + SCHEME_PATTERN + ")?" + "(//(" + USERINFO_PATTERN + "@)?" + HOST_PATTERN + "(:" + PORT_PATTERN +
|
||||
")?" + ")?" + PATH_PATTERN + "(\\?" + QUERY_PATTERN + ")?" + "(#" + LAST_PATTERN + ")?");
|
||||
|
||||
private static final Pattern HTTP_URL_PATTERN = Pattern.compile(
|
||||
"^" + HTTP_PATTERN + "(//(" + USERINFO_PATTERN + "@)?" + HOST_PATTERN + "(:" + PORT_PATTERN + ")?" + ")?" +
|
||||
PATH_PATTERN + "(\\?" + LAST_PATTERN + ")?");
|
||||
// encoding
|
||||
|
||||
/**
|
||||
* Encodes the given source URI into an encoded String. All various URI components are
|
||||
* encoded according to their respective valid character sets.
|
||||
* <p><strong>Note</strong> that this method does not attempt to encode "=" and "&"
|
||||
* characters in query parameter names and query parameter values because they cannot
|
||||
* be parsed in a reliable way. Instead use:
|
||||
* <pre>
|
||||
* UriComponents uriComponents = UriComponentsBuilder.fromUri("/path?name={value}").buildAndExpand("a=b");
|
||||
* String encodedUri = uriComponents.encode().toUriString();
|
||||
* </pre>
|
||||
* @param uri the URI to be encoded
|
||||
* @param encoding the character encoding to encode to
|
||||
* @return the encoded URI
|
||||
* @throws IllegalArgumentException when the given uri parameter is not a valid URI
|
||||
* @throws UnsupportedEncodingException when the given encoding parameter is not supported
|
||||
* @deprecated in favor of {@link UriComponentsBuilder}; see note about query param encoding
|
||||
*/
|
||||
public static String encodeUri(String uri, String encoding) throws UnsupportedEncodingException {
|
||||
UriComponents uriComponents = UriComponentsBuilder.fromUriString(uri).build();
|
||||
UriComponents encoded = uriComponents.encode(encoding);
|
||||
return encoded.toUriString();
|
||||
}
|
||||
Assert.notNull(uri, "'uri' must not be null");
|
||||
Assert.hasLength(encoding, "'encoding' must not be empty");
|
||||
Matcher m = URI_PATTERN.matcher(uri);
|
||||
if (m.matches()) {
|
||||
String scheme = m.group(2);
|
||||
String authority = m.group(3);
|
||||
String userinfo = m.group(5);
|
||||
String host = m.group(6);
|
||||
String port = m.group(8);
|
||||
String path = m.group(9);
|
||||
String query = m.group(11);
|
||||
String fragment = m.group(13);
|
||||
|
||||
return encodeUriComponents(scheme, authority, userinfo, host, port, path, query, fragment, encoding);
|
||||
}
|
||||
else {
|
||||
throw new IllegalArgumentException("[" + uri + "] is not a valid URI");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Encodes the given HTTP URI into an encoded String. All various URI components are
|
||||
* encoded according to their respective valid character sets.
|
||||
* <p><strong>Note</strong> that this method does not support fragments ({@code #}),
|
||||
* as these are not supposed to be sent to the server, but retained by the client.
|
||||
* <p><strong>Note</strong> that this method does not attempt to encode "=" and "&"
|
||||
* characters in query parameter names and query parameter values because they cannot
|
||||
* be parsed in a reliable way. Instead use:
|
||||
* <pre>
|
||||
* UriComponents uriComponents = UriComponentsBuilder.fromHttpUrl("/path?name={value}").buildAndExpand("a=b");
|
||||
* String encodedUri = uriComponents.encode().toUriString();
|
||||
* </pre>
|
||||
* @param httpUrl the HTTP URL to be encoded
|
||||
* @param encoding the character encoding to encode to
|
||||
* @return the encoded URL
|
||||
* @throws IllegalArgumentException when the given uri parameter is not a valid URI
|
||||
* @throws UnsupportedEncodingException when the given encoding parameter is not supported
|
||||
* @deprecated in favor of {@link UriComponentsBuilder}; see note about query param encoding
|
||||
*/
|
||||
public static String encodeHttpUrl(String httpUrl, String encoding) throws UnsupportedEncodingException {
|
||||
UriComponents uriComponents = UriComponentsBuilder.fromHttpUrl(httpUrl).build();
|
||||
UriComponents encoded = uriComponents.encode(encoding);
|
||||
return encoded.toUriString();
|
||||
Assert.notNull(httpUrl, "'httpUrl' must not be null");
|
||||
Assert.hasLength(encoding, "'encoding' must not be empty");
|
||||
Matcher m = HTTP_URL_PATTERN.matcher(httpUrl);
|
||||
if (m.matches()) {
|
||||
String scheme = m.group(1);
|
||||
String authority = m.group(2);
|
||||
String userinfo = m.group(4);
|
||||
String host = m.group(5);
|
||||
String portString = m.group(7);
|
||||
String path = m.group(8);
|
||||
String query = m.group(10);
|
||||
|
||||
return encodeUriComponents(scheme, authority, userinfo, host, portString, path, query, null, encoding);
|
||||
}
|
||||
else {
|
||||
throw new IllegalArgumentException("[" + httpUrl + "] is not a valid HTTP URL");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -87,20 +158,48 @@ public abstract class UriUtils {
|
|||
* @return the encoded URI
|
||||
* @throws IllegalArgumentException when the given uri parameter is not a valid URI
|
||||
* @throws UnsupportedEncodingException when the given encoding parameter is not supported
|
||||
* @deprecated in favor of {@link UriComponentsBuilder}
|
||||
*/
|
||||
public static String encodeUriComponents(String scheme, String authority, String userInfo,
|
||||
String host, String port, String path, String query, String fragment, String encoding)
|
||||
throws UnsupportedEncodingException {
|
||||
|
||||
int portAsInt = (port != null ? Integer.parseInt(port) : -1);
|
||||
Assert.hasLength(encoding, "'encoding' must not be empty");
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
UriComponentsBuilder builder = UriComponentsBuilder.newInstance();
|
||||
builder.scheme(scheme).userInfo(userInfo).host(host).port(portAsInt);
|
||||
builder.path(path).query(query).fragment(fragment);
|
||||
if (scheme != null) {
|
||||
sb.append(encodeScheme(scheme, encoding));
|
||||
sb.append(':');
|
||||
}
|
||||
|
||||
UriComponents encoded = builder.build().encode(encoding);
|
||||
if (authority != null) {
|
||||
sb.append("//");
|
||||
if (userInfo != null) {
|
||||
sb.append(encodeUserInfo(userInfo, encoding));
|
||||
sb.append('@');
|
||||
}
|
||||
if (host != null) {
|
||||
sb.append(encodeHost(host, encoding));
|
||||
}
|
||||
if (port != null) {
|
||||
sb.append(':');
|
||||
sb.append(encodePort(port, encoding));
|
||||
}
|
||||
}
|
||||
|
||||
return encoded.toUriString();
|
||||
sb.append(encodePath(path, encoding));
|
||||
|
||||
if (query != null) {
|
||||
sb.append('?');
|
||||
sb.append(encodeQuery(query, encoding));
|
||||
}
|
||||
|
||||
if (fragment != null) {
|
||||
sb.append('#');
|
||||
sb.append(encodeFragment(fragment, encoding));
|
||||
}
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2010 the original author or authors.
|
||||
* Copyright 2002-2012 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,38 +16,110 @@
|
|||
|
||||
package org.springframework.http;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/** @author Arjen Poutsma */
|
||||
public class HttpStatusTests {
|
||||
|
||||
private int[] registryValues =
|
||||
new int[]{100, 101, 102, 200, 201, 202, 203, 204, 205, 206, 207, 208, 226, 300, 301, 302, 303, 304, 305,
|
||||
307, 400, 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, 414, 415, 416, 417, 422,
|
||||
423, 424, 426, 500, 501, 502, 503, 504, 505, 506, 507, 508, 510,};
|
||||
private Map<Integer, String> statusCodes = new LinkedHashMap<Integer, String>();
|
||||
|
||||
private String[] registryDescriptions =
|
||||
new String[]{"CONTINUE", "SWITCHING_PROTOCOLS", "PROCESSING", "OK", "CREATED", "ACCEPTED",
|
||||
"NON_AUTHORITATIVE_INFORMATION", "NO_CONTENT", "RESET_CONTENT", "PARTIAL_CONTENT", "MULTI_STATUS",
|
||||
"ALREADY_REPORTED", "IM_USED", "MULTIPLE_CHOICES", "MOVED_PERMANENTLY", "FOUND", "SEE_OTHER",
|
||||
"NOT_MODIFIED", "USE_PROXY", "TEMPORARY_REDIRECT", "BAD_REQUEST", "UNAUTHORIZED",
|
||||
"PAYMENT_REQUIRED", "FORBIDDEN", "NOT_FOUND", "METHOD_NOT_ALLOWED", "NOT_ACCEPTABLE",
|
||||
"PROXY_AUTHENTICATION_REQUIRED", "REQUEST_TIMEOUT", "CONFLICT", "GONE", "LENGTH_REQUIRED",
|
||||
"PRECONDITION_FAILED", "REQUEST_ENTITY_TOO_LARGE", "REQUEST_URI_TOO_LONG", "UNSUPPORTED_MEDIA_TYPE",
|
||||
"REQUESTED_RANGE_NOT_SATISFIABLE", "EXPECTATION_FAILED", "UNPROCESSABLE_ENTITY", "LOCKED",
|
||||
"FAILED_DEPENDENCY", "UPGRADE_REQUIRED", "INTERNAL_SERVER_ERROR", "NOT_IMPLEMENTED", "BAD_GATEWAY",
|
||||
"SERVICE_UNAVAILABLE", "GATEWAY_TIMEOUT", "HTTP_VERSION_NOT_SUPPORTED", "VARIANT_ALSO_NEGOTIATES",
|
||||
"INSUFFICIENT_STORAGE", "LOOP_DETECTED", "NOT_EXTENDED",};
|
||||
@Before
|
||||
public void createStatusCodes() {
|
||||
statusCodes.put(100, "CONTINUE");
|
||||
statusCodes.put(101, "SWITCHING_PROTOCOLS");
|
||||
statusCodes.put(102, "PROCESSING");
|
||||
statusCodes.put(103, "CHECKPOINT");
|
||||
|
||||
@Test
|
||||
public void registryValues() {
|
||||
for (int i = 0; i < registryValues.length; i++) {
|
||||
HttpStatus status = HttpStatus.valueOf(registryValues[i]);
|
||||
assertEquals("Invalid value", registryValues[i], status.value());
|
||||
assertEquals("Invalid descripion", registryDescriptions[i], status.name());
|
||||
}
|
||||
statusCodes.put(200, "OK");
|
||||
statusCodes.put(201, "CREATED");
|
||||
statusCodes.put(202, "ACCEPTED");
|
||||
statusCodes.put(203, "NON_AUTHORITATIVE_INFORMATION");
|
||||
statusCodes.put(204, "NO_CONTENT");
|
||||
statusCodes.put(205, "RESET_CONTENT");
|
||||
statusCodes.put(206, "PARTIAL_CONTENT");
|
||||
statusCodes.put(207, "MULTI_STATUS");
|
||||
statusCodes.put(208, "ALREADY_REPORTED");
|
||||
statusCodes.put(226, "IM_USED");
|
||||
|
||||
statusCodes.put(300, "MULTIPLE_CHOICES");
|
||||
statusCodes.put(301, "MOVED_PERMANENTLY");
|
||||
statusCodes.put(302, "FOUND");
|
||||
statusCodes.put(303, "SEE_OTHER");
|
||||
statusCodes.put(304, "NOT_MODIFIED");
|
||||
statusCodes.put(305, "USE_PROXY");
|
||||
statusCodes.put(307, "TEMPORARY_REDIRECT");
|
||||
statusCodes.put(308, "RESUME_INCOMPLETE");
|
||||
|
||||
statusCodes.put(400, "BAD_REQUEST");
|
||||
statusCodes.put(401, "UNAUTHORIZED");
|
||||
statusCodes.put(402, "PAYMENT_REQUIRED");
|
||||
statusCodes.put(403, "FORBIDDEN");
|
||||
statusCodes.put(404, "NOT_FOUND");
|
||||
statusCodes.put(405, "METHOD_NOT_ALLOWED");
|
||||
statusCodes.put(406, "NOT_ACCEPTABLE");
|
||||
statusCodes.put(407, "PROXY_AUTHENTICATION_REQUIRED");
|
||||
statusCodes.put(408, "REQUEST_TIMEOUT");
|
||||
statusCodes.put(409, "CONFLICT");
|
||||
statusCodes.put(410, "GONE");
|
||||
statusCodes.put(411, "LENGTH_REQUIRED");
|
||||
statusCodes.put(412, "PRECONDITION_FAILED");
|
||||
statusCodes.put(413, "REQUEST_ENTITY_TOO_LARGE");
|
||||
statusCodes.put(414, "REQUEST_URI_TOO_LONG");
|
||||
statusCodes.put(415, "UNSUPPORTED_MEDIA_TYPE");
|
||||
statusCodes.put(416, "REQUESTED_RANGE_NOT_SATISFIABLE");
|
||||
statusCodes.put(417, "EXPECTATION_FAILED");
|
||||
statusCodes.put(418, "I_AM_A_TEAPOT");
|
||||
statusCodes.put(419, "INSUFFICIENT_SPACE_ON_RESOURCE");
|
||||
statusCodes.put(420, "METHOD_FAILURE");
|
||||
statusCodes.put(421, "DESTINATION_LOCKED");
|
||||
statusCodes.put(422, "UNPROCESSABLE_ENTITY");
|
||||
statusCodes.put(423, "LOCKED");
|
||||
statusCodes.put(424, "FAILED_DEPENDENCY");
|
||||
statusCodes.put(426, "UPGRADE_REQUIRED");
|
||||
statusCodes.put(428, "PRECONDITION_REQUIRED");
|
||||
statusCodes.put(429, "TOO_MANY_REQUESTS");
|
||||
statusCodes.put(431, "REQUEST_HEADER_FIELDS_TOO_LARGE");
|
||||
|
||||
statusCodes.put(500, "INTERNAL_SERVER_ERROR");
|
||||
statusCodes.put(501, "NOT_IMPLEMENTED");
|
||||
statusCodes.put(502, "BAD_GATEWAY");
|
||||
statusCodes.put(503, "SERVICE_UNAVAILABLE");
|
||||
statusCodes.put(504, "GATEWAY_TIMEOUT");
|
||||
statusCodes.put(505, "HTTP_VERSION_NOT_SUPPORTED");
|
||||
statusCodes.put(506, "VARIANT_ALSO_NEGOTIATES");
|
||||
statusCodes.put(507, "INSUFFICIENT_STORAGE");
|
||||
statusCodes.put(508, "LOOP_DETECTED");
|
||||
statusCodes.put(509, "BANDWIDTH_LIMIT_EXCEEDED");
|
||||
statusCodes.put(510, "NOT_EXTENDED");
|
||||
statusCodes.put(511, "NETWORK_AUTHENTICATION_REQUIRED");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void fromMapToEnum() {
|
||||
for (Map.Entry<Integer, String> entry : statusCodes.entrySet()) {
|
||||
int value = entry.getKey();
|
||||
HttpStatus status = HttpStatus.valueOf(value);
|
||||
assertEquals("Invalid value", value, status.value());
|
||||
assertEquals("Invalid name for [" + value + "]", entry.getValue(), status.name());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void fromEnumToMap() {
|
||||
|
||||
for (HttpStatus status : HttpStatus.values()) {
|
||||
int value = status.value();
|
||||
if (value == 302) {
|
||||
continue;
|
||||
}
|
||||
assertTrue("Map has no value for [" + value + "]", statusCodes.containsKey(value));
|
||||
assertEquals("Invalid name for [" + value + "]", statusCodes.get(value), status.name());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -173,9 +173,12 @@ public class MediaTypeTests {
|
|||
MediaType.parseMediaType("text/html; charset=foo-bar");
|
||||
}
|
||||
|
||||
// SPR-8917
|
||||
|
||||
@Test
|
||||
public void parseMediaTypeQuotedParameterValue() {
|
||||
MediaType.parseMediaType("audio/*;attr=\"v>alue\"");
|
||||
MediaType mediaType = MediaType.parseMediaType("audio/*;attr=\"v>alue\"");
|
||||
assertEquals("\"v>alue\"", mediaType.getParameter("attr"));
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2011 the original author or authors.
|
||||
* Copyright 2002-2012 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.
|
||||
|
|
@ -291,6 +291,10 @@ public class InterceptingClientHttpRequestFactoryTests {
|
|||
return statusCode;
|
||||
}
|
||||
|
||||
public int getRawStatusCode() throws IOException {
|
||||
return statusCode.value();
|
||||
}
|
||||
|
||||
public String getStatusText() throws IOException {
|
||||
return statusText;
|
||||
}
|
||||
|
|
@ -300,7 +304,7 @@ public class InterceptingClientHttpRequestFactoryTests {
|
|||
}
|
||||
|
||||
public InputStream getBody() throws IOException {
|
||||
return null; //To change body of implemented methods use File | Settings | File Templates.
|
||||
return null;
|
||||
}
|
||||
|
||||
public void close() {
|
||||
|
|
|
|||
|
|
@ -128,6 +128,9 @@ public class UriUtilsTests {
|
|||
assertEquals("Invalid encoded URI", "http://example.com/query=foo@bar",
|
||||
UriUtils.encodeUri("http://example.com/query=foo@bar", ENC));
|
||||
|
||||
// SPR-8974
|
||||
assertEquals("http://example.org?format=json&url=http://another.com?foo=bar",
|
||||
UriUtils.encodeUri("http://example.org?format=json&url=http://another.com?foo=bar", ENC));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
|||
Loading…
Reference in New Issue