Remove deprecated ThemeResolver support

See gh-33809
This commit is contained in:
rstoyanchev 2025-01-14 15:26:44 +00:00
parent 9ddbf800b9
commit 9f77d5ff1f
54 changed files with 39 additions and 2163 deletions

View File

@ -160,7 +160,6 @@
**** xref:web/webmvc/mvc-servlet/exceptionhandlers.adoc[]
**** xref:web/webmvc/mvc-servlet/viewresolver.adoc[]
**** xref:web/webmvc/mvc-servlet/localeresolver.adoc[]
**** xref:web/webmvc/mvc-servlet/themeresolver.adoc[]
**** xref:web/webmvc/mvc-servlet/multipart.adoc[]
**** xref:web/webmvc/mvc-servlet/logging.adoc[]
*** xref:web/webmvc/filters.adoc[]

View File

@ -43,10 +43,6 @@ The following table lists the special beans detected by the `DispatcherServlet`:
| Resolve the `Locale` a client is using and possibly their time zone, in order to be able
to offer internationalized views. See xref:web/webmvc/mvc-servlet/localeresolver.adoc[Locale].
| xref:web/webmvc/mvc-servlet/themeresolver.adoc[`ThemeResolver`]
| Resolve themes your web application can use -- for example, to offer personalized layouts.
See xref:web/webmvc/mvc-servlet/themeresolver.adoc[Themes].
| xref:web/webmvc/mvc-servlet/multipart.adoc[`MultipartResolver`]
| Abstraction for parsing a multi-part request (for example, browser form file upload) with
the help of some multipart parsing library. See xref:web/webmvc/mvc-servlet/multipart.adoc[Multipart Resolver].

View File

@ -1,92 +0,0 @@
[[mvc-themeresolver]]
= Themes
You can apply Spring Web MVC framework themes to set the overall look-and-feel of your
application, thereby enhancing user experience. A theme is a collection of static
resources, typically style sheets and images, that affect the visual style of the
application.
WARNING: as of 6.0 support for themes has been deprecated theme in favor of using CSS,
and without any special support on the server side.
[[mvc-themeresolver-defining]]
== Defining a theme
To use themes in your web application, you must set up an implementation of the
`org.springframework.ui.context.ThemeSource` interface. The `WebApplicationContext`
interface extends `ThemeSource` but delegates its responsibilities to a dedicated
implementation. By default, the delegate is an
`org.springframework.ui.context.support.ResourceBundleThemeSource` implementation that
loads properties files from the root of the classpath. To use a custom `ThemeSource`
implementation or to configure the base name prefix of the `ResourceBundleThemeSource`,
you can register a bean in the application context with the reserved name, `themeSource`.
The web application context automatically detects a bean with that name and uses it.
When you use the `ResourceBundleThemeSource`, a theme is defined in a simple properties
file. The properties file lists the resources that make up the theme, as the following example shows:
[literal,subs="verbatim,quotes"]
----
styleSheet=/themes/cool/style.css
background=/themes/cool/img/coolBg.jpg
----
The keys of the properties are the names that refer to the themed elements from view
code. For a JSP, you typically do this using the `spring:theme` custom tag, which is
very similar to the `spring:message` tag. The following JSP fragment uses the theme
defined in the previous example to customize the look and feel:
[source,xml,indent=0,subs="verbatim,quotes"]
----
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags"%>
<html>
<head>
<link rel="stylesheet" href="<spring:theme code='styleSheet'/>" type="text/css"/>
</head>
<body style="background=<spring:theme code='background'/>">
...
</body>
</html>
----
By default, the `ResourceBundleThemeSource` uses an empty base name prefix. As a result,
the properties files are loaded from the root of the classpath. Thus, you would put the
`cool.properties` theme definition in a directory at the root of the classpath (for
example, in `/WEB-INF/classes`). The `ResourceBundleThemeSource` uses the standard Java
resource bundle loading mechanism, allowing for full internationalization of themes. For
example, we could have a `/WEB-INF/classes/cool_nl.properties` that references a special
background image with Dutch text on it.
[[mvc-themeresolver-resolving]]
== Resolving Themes
After you define themes, as described in the xref:web/webmvc/mvc-servlet/themeresolver.adoc#mvc-themeresolver-defining[preceding section],
you decide which theme to use. The `DispatcherServlet` looks for a bean named `themeResolver`
to find out which `ThemeResolver` implementation to use. A theme resolver works in much the same
way as a `LocaleResolver`. It detects the theme to use for a particular request and can also
alter the request's theme. The following table describes the theme resolvers provided by Spring:
[[mvc-theme-resolver-impls-tbl]]
.ThemeResolver implementations
[cols="1,4"]
|===
| Class | Description
| `FixedThemeResolver`
| Selects a fixed theme, set by using the `defaultThemeName` property.
| `SessionThemeResolver`
| The theme is maintained in the user's HTTP session. It needs to be set only once for
each session but is not persisted between sessions.
| `CookieThemeResolver`
| The selected theme is stored in a cookie on the client.
|===
Spring also provides a `ThemeChangeInterceptor` that lets theme changes on every
request with a simple request parameter.

View File

@ -1,46 +0,0 @@
/*
* Copyright 2002-2022 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
*
* https://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.ui.context;
import org.jspecify.annotations.Nullable;
/**
* Sub-interface of ThemeSource to be implemented by objects that
* can resolve theme messages hierarchically.
*
* @author Jean-Pierre Pawlak
* @author Juergen Hoeller
* @deprecated as of 6.0 in favor of using CSS, without direct replacement
*/
@Deprecated(since = "6.0")
public interface HierarchicalThemeSource extends ThemeSource {
/**
* Set the parent that will be used to try to resolve theme messages
* that this object can't resolve.
* @param parent the parent ThemeSource that will be used to
* resolve messages that this object can't resolve.
* May be {@code null}, in which case no further resolution is possible.
*/
void setParentThemeSource(@Nullable ThemeSource parent);
/**
* Return the parent of this ThemeSource, or {@code null} if none.
*/
@Nullable ThemeSource getParentThemeSource();
}

View File

@ -1,49 +0,0 @@
/*
* Copyright 2002-2022 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
*
* https://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.ui.context;
import org.springframework.context.MessageSource;
/**
* A Theme can resolve theme-specific messages, codes, file paths, etc.
* (e&#46;g&#46; CSS and image files in a web environment).
* The exposed {@link org.springframework.context.MessageSource} supports
* theme-specific parameterization and internationalization.
*
* @author Juergen Hoeller
* @since 17.06.2003
* @see ThemeSource
* @see org.springframework.web.servlet.ThemeResolver
* @deprecated as of 6.0 in favor of using CSS, without direct replacement
*/
@Deprecated(since = "6.0")
public interface Theme {
/**
* Return the name of the theme.
* @return the name of the theme (never {@code null})
*/
String getName();
/**
* Return the specific MessageSource that resolves messages
* with respect to this theme.
* @return the theme-specific MessageSource (never {@code null})
*/
MessageSource getMessageSource();
}

View File

@ -1,47 +0,0 @@
/*
* Copyright 2002-2022 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
*
* https://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.ui.context;
import org.jspecify.annotations.Nullable;
/**
* Interface to be implemented by objects that can resolve {@link Theme Themes}.
* This enables parameterization and internationalization of messages
* for a given 'theme'.
*
* @author Jean-Pierre Pawlak
* @author Juergen Hoeller
* @see Theme
* @deprecated as of 6.0 in favor of using CSS, without direct replacement
*/
@Deprecated(since = "6.0")
public interface ThemeSource {
/**
* Return the Theme instance for the given theme name.
* <p>The returned Theme will resolve theme-specific messages, codes,
* file paths, etc (for example, CSS and image files in a web environment).
* @param themeName the name of the theme
* @return the corresponding Theme, or {@code null} if none defined.
* Note that, by convention, a ThemeSource should at least be able to
* return a default Theme for the default theme name "theme" but may also
* return default Themes for other theme names.
* @see org.springframework.web.servlet.theme.AbstractThemeResolver#ORIGINAL_DEFAULT_THEME_NAME
*/
@Nullable Theme getTheme(String themeName);
}

View File

@ -1,8 +0,0 @@
/**
* Contains classes defining the application context subinterface
* for UI applications. The theme feature is added here.
*/
@NullMarked
package org.springframework.ui.context;
import org.jspecify.annotations.NullMarked;

View File

@ -1,64 +0,0 @@
/*
* Copyright 2002-2022 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
*
* https://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.ui.context.support;
import org.jspecify.annotations.Nullable;
import org.springframework.ui.context.HierarchicalThemeSource;
import org.springframework.ui.context.Theme;
import org.springframework.ui.context.ThemeSource;
/**
* Empty ThemeSource that delegates all calls to the parent ThemeSource.
* If no parent is available, it simply won't resolve any theme.
*
* <p>Used as placeholder by UiApplicationContextUtils, if a context doesn't
* define its own ThemeSource. Not intended for direct use in applications.
*
* @author Juergen Hoeller
* @since 1.2.4
* @see UiApplicationContextUtils
* @deprecated as of 6.0 in favor of using CSS, without direct replacement
*/
@Deprecated(since = "6.0")
public class DelegatingThemeSource implements HierarchicalThemeSource {
private @Nullable ThemeSource parentThemeSource;
@Override
public void setParentThemeSource(@Nullable ThemeSource parentThemeSource) {
this.parentThemeSource = parentThemeSource;
}
@Override
public @Nullable ThemeSource getParentThemeSource() {
return this.parentThemeSource;
}
@Override
public @Nullable Theme getTheme(String themeName) {
if (this.parentThemeSource != null) {
return this.parentThemeSource.getTheme(themeName);
}
else {
return null;
}
}
}

View File

@ -1,198 +0,0 @@
/*
* Copyright 2002-2023 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
*
* https://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.ui.context.support;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jspecify.annotations.Nullable;
import org.springframework.beans.factory.BeanClassLoaderAware;
import org.springframework.context.HierarchicalMessageSource;
import org.springframework.context.MessageSource;
import org.springframework.context.support.ResourceBundleMessageSource;
import org.springframework.ui.context.HierarchicalThemeSource;
import org.springframework.ui.context.Theme;
import org.springframework.ui.context.ThemeSource;
/**
* {@link ThemeSource} implementation that looks up an individual
* {@link java.util.ResourceBundle} per theme. The theme name gets
* interpreted as ResourceBundle basename, supporting a common
* basename prefix for all themes.
*
* @author Jean-Pierre Pawlak
* @author Juergen Hoeller
* @see #setBasenamePrefix
* @see java.util.ResourceBundle
* @see org.springframework.context.support.ResourceBundleMessageSource
* @deprecated as of 6.0 in favor of using CSS, without direct replacement
*/
@Deprecated(since = "6.0")
public class ResourceBundleThemeSource implements HierarchicalThemeSource, BeanClassLoaderAware {
protected final Log logger = LogFactory.getLog(getClass());
private @Nullable ThemeSource parentThemeSource;
private String basenamePrefix = "";
private @Nullable String defaultEncoding;
private @Nullable Boolean fallbackToSystemLocale;
private @Nullable ClassLoader beanClassLoader;
/** Map from theme name to Theme instance. */
private final Map<String, Theme> themeCache = new ConcurrentHashMap<>();
@Override
public void setParentThemeSource(@Nullable ThemeSource parent) {
this.parentThemeSource = parent;
// Update existing Theme objects.
// Usually there shouldn't be any at the time of this call.
synchronized (this.themeCache) {
for (Theme theme : this.themeCache.values()) {
initParent(theme);
}
}
}
@Override
public @Nullable ThemeSource getParentThemeSource() {
return this.parentThemeSource;
}
/**
* Set the prefix that gets applied to the ResourceBundle basenames,
* i.e. the theme names.
* For example: basenamePrefix="test.", themeName="theme" &rarr; basename="test.theme".
* <p>Note that ResourceBundle names are effectively classpath locations: As a
* consequence, the JDK's standard ResourceBundle treats dots as package separators.
* This means that "test.theme" is effectively equivalent to "test/theme",
* just like it is for programmatic {@code java.util.ResourceBundle} usage.
* @see java.util.ResourceBundle#getBundle(String)
*/
public void setBasenamePrefix(@Nullable String basenamePrefix) {
this.basenamePrefix = (basenamePrefix != null ? basenamePrefix : "");
}
/**
* Set the default charset to use for parsing resource bundle files.
* <p>{@link ResourceBundleMessageSource}'s default is the
* {@code java.util.ResourceBundle} default encoding: ISO-8859-1.
* @since 4.2
* @see ResourceBundleMessageSource#setDefaultEncoding
*/
public void setDefaultEncoding(@Nullable String defaultEncoding) {
this.defaultEncoding = defaultEncoding;
}
/**
* Set whether to fall back to the system Locale if no files for a
* specific Locale have been found.
* <p>{@link ResourceBundleMessageSource}'s default is "true".
* @since 4.2
* @see ResourceBundleMessageSource#setFallbackToSystemLocale
*/
public void setFallbackToSystemLocale(boolean fallbackToSystemLocale) {
this.fallbackToSystemLocale = fallbackToSystemLocale;
}
@Override
public void setBeanClassLoader(@Nullable ClassLoader beanClassLoader) {
this.beanClassLoader = beanClassLoader;
}
/**
* This implementation returns a SimpleTheme instance, holding a
* ResourceBundle-based MessageSource whose basename corresponds to
* the given theme name (prefixed by the configured "basenamePrefix").
* <p>SimpleTheme instances are cached per theme name. Use a reloadable
* MessageSource if themes should reflect changes to the underlying files.
* @see #setBasenamePrefix
* @see #createMessageSource
*/
@Override
public @Nullable Theme getTheme(String themeName) {
Theme theme = this.themeCache.get(themeName);
if (theme == null) {
synchronized (this.themeCache) {
theme = this.themeCache.get(themeName);
if (theme == null) {
String basename = this.basenamePrefix + themeName;
MessageSource messageSource = createMessageSource(basename);
theme = new SimpleTheme(themeName, messageSource);
initParent(theme);
this.themeCache.put(themeName, theme);
if (logger.isDebugEnabled()) {
logger.debug("Theme created: name '" + themeName + "', basename [" + basename + "]");
}
}
}
}
return theme;
}
/**
* Create a MessageSource for the given basename,
* to be used as MessageSource for the corresponding theme.
* <p>Default implementation creates a ResourceBundleMessageSource.
* for the given basename. A subclass could create a specifically
* configured ReloadableResourceBundleMessageSource, for example.
* @param basename the basename to create a MessageSource for
* @return the MessageSource
* @see org.springframework.context.support.ResourceBundleMessageSource
* @see org.springframework.context.support.ReloadableResourceBundleMessageSource
*/
protected MessageSource createMessageSource(String basename) {
ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
messageSource.setBasename(basename);
if (this.defaultEncoding != null) {
messageSource.setDefaultEncoding(this.defaultEncoding);
}
if (this.fallbackToSystemLocale != null) {
messageSource.setFallbackToSystemLocale(this.fallbackToSystemLocale);
}
if (this.beanClassLoader != null) {
messageSource.setBeanClassLoader(this.beanClassLoader);
}
return messageSource;
}
/**
* Initialize the MessageSource of the given theme with the
* one from the corresponding parent of this ThemeSource.
* @param theme the Theme to (re-)initialize
*/
protected void initParent(Theme theme) {
if (theme.getMessageSource() instanceof HierarchicalMessageSource messageSource) {
if (getParentThemeSource() != null && messageSource.getParentMessageSource() == null) {
Theme parentTheme = getParentThemeSource().getTheme(theme.getName());
if (parentTheme != null) {
messageSource.setParentMessageSource(parentTheme.getMessageSource());
}
}
}
}
}

View File

@ -1,62 +0,0 @@
/*
* Copyright 2002-2022 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
*
* https://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.ui.context.support;
import org.springframework.context.MessageSource;
import org.springframework.ui.context.Theme;
import org.springframework.util.Assert;
/**
* Default {@link Theme} implementation, wrapping a name and an
* underlying {@link org.springframework.context.MessageSource}.
*
* @author Juergen Hoeller
* @since 17.06.2003
* @deprecated as of 6.0 in favor of using CSS, without direct replacement
*/
@Deprecated(since = "6.0")
public class SimpleTheme implements Theme {
private final String name;
private final MessageSource messageSource;
/**
* Create a SimpleTheme.
* @param name the name of the theme
* @param messageSource the MessageSource that resolves theme messages
*/
public SimpleTheme(String name, MessageSource messageSource) {
Assert.notNull(name, "Name must not be null");
Assert.notNull(messageSource, "MessageSource must not be null");
this.name = name;
this.messageSource = messageSource;
}
@Override
public final String getName() {
return this.name;
}
@Override
public final MessageSource getMessageSource() {
return this.messageSource;
}
}

View File

@ -1,93 +0,0 @@
/*
* Copyright 2002-2023 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
*
* https://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.ui.context.support;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.ui.context.HierarchicalThemeSource;
import org.springframework.ui.context.ThemeSource;
/**
* Utility class for UI application context implementations.
* Provides support for a special bean named "themeSource",
* of type {@link org.springframework.ui.context.ThemeSource}.
*
* @author Jean-Pierre Pawlak
* @author Juergen Hoeller
* @since 17.06.2003
* @deprecated as of 6.0 in favor of using CSS, without direct replacement
*/
@Deprecated(since = "6.0")
public abstract class UiApplicationContextUtils {
/**
* Name of the ThemeSource bean in the factory.
* If none is supplied, theme resolution is delegated to the parent.
* @see org.springframework.ui.context.ThemeSource
*/
public static final String THEME_SOURCE_BEAN_NAME = "themeSource";
private static final Log logger = LogFactory.getLog(UiApplicationContextUtils.class);
/**
* Initialize the ThemeSource for the given application context,
* autodetecting a bean with the name "themeSource". If no such
* bean is found, a default (empty) ThemeSource will be used.
* @param context current application context
* @return the initialized theme source (will never be {@code null})
* @see #THEME_SOURCE_BEAN_NAME
*/
public static ThemeSource initThemeSource(ApplicationContext context) {
if (context.containsLocalBean(THEME_SOURCE_BEAN_NAME)) {
ThemeSource themeSource = context.getBean(THEME_SOURCE_BEAN_NAME, ThemeSource.class);
// Make ThemeSource aware of parent ThemeSource.
if (context.getParent() instanceof ThemeSource pts && themeSource instanceof HierarchicalThemeSource hts) {
if (hts.getParentThemeSource() == null) {
// Only set parent context as parent ThemeSource if no parent ThemeSource
// registered already.
hts.setParentThemeSource(pts);
}
}
if (logger.isDebugEnabled()) {
logger.debug("Using ThemeSource [" + themeSource + "]");
}
return themeSource;
}
else {
// Use default ThemeSource to be able to accept getTheme calls, either
// delegating to parent context's default or to local ResourceBundleThemeSource.
HierarchicalThemeSource themeSource = null;
if (context.getParent() instanceof ThemeSource pts) {
themeSource = new DelegatingThemeSource();
themeSource.setParentThemeSource(pts);
}
else {
themeSource = new ResourceBundleThemeSource();
}
if (logger.isDebugEnabled()) {
logger.debug("Unable to locate ThemeSource with name '" + THEME_SOURCE_BEAN_NAME +
"': using default [" + themeSource + "]");
}
return themeSource;
}
}
}

View File

@ -1,8 +0,0 @@
/**
* Classes supporting the org.springframework.ui.context package.
* Provides support classes for specialized UI contexts, for example, for web UIs.
*/
@NullMarked
package org.springframework.ui.context.support;
import org.jspecify.annotations.NullMarked;

View File

@ -395,8 +395,6 @@ public class StandaloneMockMvcBuilder extends AbstractMockMvcBuilder<StandaloneM
wac.addBeans(initViewResolvers(wac));
wac.addBean(DispatcherServlet.LOCALE_RESOLVER_BEAN_NAME, this.localeResolver);
wac.addBean(DispatcherServlet.THEME_RESOLVER_BEAN_NAME,
new org.springframework.web.servlet.theme.FixedThemeResolver());
wac.addBean(DispatcherServlet.REQUEST_TO_VIEW_NAME_TRANSLATOR_BEAN_NAME,
new DefaultRequestToViewNameTranslator());

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 the original author or authors.
* Copyright 2002-2025 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,9 +25,6 @@ import org.springframework.context.support.AbstractRefreshableConfigApplicationC
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.ui.context.Theme;
import org.springframework.ui.context.ThemeSource;
import org.springframework.ui.context.support.UiApplicationContextUtils;
import org.springframework.util.Assert;
import org.springframework.web.context.ConfigurableWebApplicationContext;
import org.springframework.web.context.ConfigurableWebEnvironment;
@ -53,12 +50,6 @@ import org.springframework.web.context.ServletContextAware;
* can be accessed via "file:" URLs, as implemented by
* {@link org.springframework.core.io.DefaultResourceLoader}.
*
* <p>In addition to the special beans detected by
* {@link org.springframework.context.support.AbstractApplicationContext},
* this class detects a bean of type {@link org.springframework.ui.context.ThemeSource}
* in the context, under the special bean name "themeSource".
* Theme support is deprecated as of 6.0 with no direct replacement.
*
* <p><b>This is the web context to be subclassed for a different bean definition format.</b>
* Such a context implementation can be specified as "contextClass" context-param
* for {@link org.springframework.web.context.ContextLoader} or as "contextClass"
@ -80,7 +71,7 @@ import org.springframework.web.context.ServletContextAware;
*/
@SuppressWarnings("deprecation")
public abstract class AbstractRefreshableWebApplicationContext extends AbstractRefreshableConfigApplicationContext
implements ConfigurableWebApplicationContext, ThemeSource {
implements ConfigurableWebApplicationContext {
/** Servlet context that this context runs in. */
private @Nullable ServletContext servletContext;
@ -91,9 +82,6 @@ public abstract class AbstractRefreshableWebApplicationContext extends AbstractR
/** Namespace of this context, or {@code null} if root. */
private @Nullable String namespace;
/** the ThemeSource for this ApplicationContext. */
private @Nullable ThemeSource themeSource;
public AbstractRefreshableWebApplicationContext() {
setDisplayName("Root WebApplicationContext");
@ -187,14 +175,6 @@ public abstract class AbstractRefreshableWebApplicationContext extends AbstractR
return new ServletContextResourcePatternResolver(this);
}
/**
* Initialize the theme capability.
*/
@Override
protected void onRefresh() {
this.themeSource = UiApplicationContextUtils.initThemeSource(this);
}
/**
* {@inheritDoc}
* <p>Replace {@code Servlet}-related property sources.
@ -207,11 +187,4 @@ public abstract class AbstractRefreshableWebApplicationContext extends AbstractR
}
}
@Override
@Deprecated
public @Nullable Theme getTheme(String themeName) {
Assert.state(this.themeSource != null, "No ThemeSource available");
return this.themeSource.getTheme(themeName);
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2024 the original author or authors.
* Copyright 2002-2025 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,9 +26,6 @@ import org.springframework.context.support.GenericApplicationContext;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.ui.context.Theme;
import org.springframework.ui.context.ThemeSource;
import org.springframework.ui.context.support.UiApplicationContextUtils;
import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
@ -49,11 +46,6 @@ import org.springframework.web.context.ServletContextAware;
* the web app root &mdash; can be accessed via {@code file:} URLs, as implemented
* by {@code AbstractApplicationContext}.
*
* <p>In addition to the special beans detected by
* {@link org.springframework.context.support.AbstractApplicationContext AbstractApplicationContext},
* this class detects a {@link ThemeSource} bean in the context, with the name "themeSource".
* Theme support is deprecated as of 6.0 with no direct replacement.
*
* <p>If you wish to register annotated <em>component classes</em> with a
* {@code GenericWebApplicationContext}, you can use an
* {@link org.springframework.context.annotation.AnnotatedBeanDefinitionReader
@ -78,14 +70,11 @@ import org.springframework.web.context.ServletContextAware;
* @author Sam Brannen
* @since 1.2
*/
@SuppressWarnings("deprecation")
public class GenericWebApplicationContext extends GenericApplicationContext
implements ConfigurableWebApplicationContext, ThemeSource {
implements ConfigurableWebApplicationContext {
private @Nullable ServletContext servletContext;
private @Nullable ThemeSource themeSource;
/**
* Create a new {@code GenericWebApplicationContext}.
@ -189,14 +178,6 @@ public class GenericWebApplicationContext extends GenericApplicationContext
return new ServletContextResourcePatternResolver(this);
}
/**
* Initialize the theme capability.
*/
@Override
protected void onRefresh() {
this.themeSource = UiApplicationContextUtils.initThemeSource(this);
}
/**
* {@inheritDoc}
* <p>Replace {@code Servlet}-related property sources.
@ -209,13 +190,6 @@ public class GenericWebApplicationContext extends GenericApplicationContext
}
}
@Override
@Deprecated
public @Nullable Theme getTheme(String themeName) {
Assert.state(this.themeSource != null, "No ThemeSource available");
return this.themeSource.getTheme(themeName);
}
// ---------------------------------------------------------------------
// Pseudo-implementation of ConfigurableWebApplicationContext

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 the original author or authors.
* Copyright 2002-2025 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,9 +25,6 @@ import org.springframework.context.support.StaticApplicationContext;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.ui.context.Theme;
import org.springframework.ui.context.ThemeSource;
import org.springframework.ui.context.support.UiApplicationContextUtils;
import org.springframework.util.Assert;
import org.springframework.web.context.ConfigurableWebApplicationContext;
import org.springframework.web.context.ServletConfigAware;
@ -46,19 +43,11 @@ import org.springframework.web.context.ServletContextAware;
* can be accessed via "file:" URLs, as implemented by
* {@link org.springframework.core.io.DefaultResourceLoader}.
*
* <p>In addition to the special beans detected by
* {@link org.springframework.context.support.AbstractApplicationContext},
* this class detects a bean of type {@link org.springframework.ui.context.ThemeSource}
* in the context, under the special bean name "themeSource".
* Theme support is deprecated as of 6.0 with no direct replacement.
*
* @author Rod Johnson
* @author Juergen Hoeller
* @see org.springframework.ui.context.ThemeSource
*/
@SuppressWarnings("deprecation")
public class StaticWebApplicationContext extends StaticApplicationContext
implements ConfigurableWebApplicationContext, ThemeSource {
implements ConfigurableWebApplicationContext {
private @Nullable ServletContext servletContext;
@ -66,8 +55,6 @@ public class StaticWebApplicationContext extends StaticApplicationContext
private @Nullable String namespace;
private @Nullable ThemeSource themeSource;
public StaticWebApplicationContext() {
setDisplayName("Root WebApplicationContext");
@ -177,25 +164,10 @@ public class StaticWebApplicationContext extends StaticApplicationContext
return new StandardServletEnvironment();
}
/**
* Initialize the theme capability.
*/
@Override
protected void onRefresh() {
this.themeSource = UiApplicationContextUtils.initThemeSource(this);
}
@Override
protected void initPropertySources() {
WebApplicationContextUtils.initServletPropertySources(getEnvironment().getPropertySources(),
this.servletContext, this.servletConfig);
}
@Override
@Deprecated
public @Nullable Theme getTheme(String themeName) {
Assert.state(this.themeSource != null, "No ThemeSource available");
return this.themeSource.getTheme(themeName);
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2024 the original author or authors.
* Copyright 2002-2025 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.
@ -124,12 +124,6 @@ import org.springframework.web.util.WebUtils;
* Out-of-the-box implementations work via HTTP accept header, cookie, or session.
* The LocaleResolver bean name is "localeResolver"; default is
* {@link org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver}.
*
* <li>Its theme resolution strategy is determined by a {@link ThemeResolver}.
* Implementations for a fixed theme and for cookie and session storage are included.
* The ThemeResolver bean name is "themeResolver"; default is
* {@link org.springframework.web.servlet.theme.FixedThemeResolver}.
* Theme support is deprecated as of 6.0 with no direct replacement.
* </ul>
*
* <p><b>NOTE: The {@code @RequestMapping} annotation will only be processed if a
@ -169,13 +163,6 @@ public class DispatcherServlet extends FrameworkServlet {
/** Well-known name for the LocaleResolver object in the bean factory for this namespace. */
public static final String LOCALE_RESOLVER_BEAN_NAME = "localeResolver";
/**
* Well-known name for the ThemeResolver object in the bean factory for this namespace.
* @deprecated as of 6.0, with no direct replacement
*/
@Deprecated
public static final String THEME_RESOLVER_BEAN_NAME = "themeResolver";
/**
* Well-known name for the HandlerMapping object in the bean factory for this namespace.
* Only used when "detectAllHandlerMappings" is turned off.
@ -227,22 +214,6 @@ public class DispatcherServlet extends FrameworkServlet {
*/
public static final String LOCALE_RESOLVER_ATTRIBUTE = DispatcherServlet.class.getName() + ".LOCALE_RESOLVER";
/**
* Request attribute to hold the current ThemeResolver, retrievable by views.
* @see org.springframework.web.servlet.support.RequestContextUtils#getThemeResolver
* @deprecated as of 6.0, with no direct replacement
*/
@Deprecated
public static final String THEME_RESOLVER_ATTRIBUTE = DispatcherServlet.class.getName() + ".THEME_RESOLVER";
/**
* Request attribute to hold the current ThemeSource, retrievable by views.
* @see org.springframework.web.servlet.support.RequestContextUtils#getThemeSource
* @deprecated as of 6.0, with no direct replacement
*/
@Deprecated
public static final String THEME_SOURCE_ATTRIBUTE = DispatcherServlet.class.getName() + ".THEME_SOURCE";
/**
* Name of request attribute that holds a read-only {@code Map<String,?>}
* with "input" flash attributes saved by a previous request, if any.
@ -312,10 +283,6 @@ public class DispatcherServlet extends FrameworkServlet {
/** LocaleResolver used by this servlet. */
private @Nullable LocaleResolver localeResolver;
/** ThemeResolver used by this servlet. */
@Deprecated
private @Nullable ThemeResolver themeResolver;
/** List of HandlerMappings used by this servlet. */
private @Nullable List<HandlerMapping> handlerMappings;
@ -475,7 +442,6 @@ public class DispatcherServlet extends FrameworkServlet {
protected void initStrategies(ApplicationContext context) {
initMultipartResolver(context);
initLocaleResolver(context);
initThemeResolver(context);
initHandlerMappings(context);
initHandlerAdapters(context);
initHandlerExceptionResolvers(context);
@ -533,32 +499,6 @@ public class DispatcherServlet extends FrameworkServlet {
}
}
/**
* Initialize the ThemeResolver used by this class.
* <p>If no bean is defined with the given name in the BeanFactory for this namespace,
* we default to a FixedThemeResolver.
*/
@Deprecated
private void initThemeResolver(ApplicationContext context) {
try {
this.themeResolver = context.getBean(THEME_RESOLVER_BEAN_NAME, ThemeResolver.class);
if (logger.isTraceEnabled()) {
logger.trace("Detected " + this.themeResolver);
}
else if (logger.isDebugEnabled()) {
logger.debug("Detected " + this.themeResolver.getClass().getSimpleName());
}
}
catch (NoSuchBeanDefinitionException ex) {
// We need to use the default.
this.themeResolver = getDefaultStrategy(context, ThemeResolver.class);
if (logger.isTraceEnabled()) {
logger.trace("No ThemeResolver '" + THEME_RESOLVER_BEAN_NAME +
"': using default [" + this.themeResolver.getClass().getSimpleName() + "]");
}
}
}
/**
* Initialize the HandlerMappings used by this class.
* <p>If no HandlerMapping beans are defined in the BeanFactory for this namespace,
@ -773,19 +713,6 @@ public class DispatcherServlet extends FrameworkServlet {
}
}
/**
* Return this servlet's ThemeSource, if any; else return {@code null}.
* <p>Default is to return the WebApplicationContext as ThemeSource,
* provided that it implements the ThemeSource interface.
* @return the ThemeSource, if any
* @see #getWebApplicationContext()
*/
@Deprecated
public final org.springframework.ui.context.@Nullable ThemeSource getThemeSource() {
return (getWebApplicationContext() instanceof org.springframework.ui.context.ThemeSource themeSource ?
themeSource : null);
}
/**
* Obtain this servlet's MultipartResolver, if any.
* @return the MultipartResolver used by this servlet, or {@code null} if none
@ -920,8 +847,6 @@ public class DispatcherServlet extends FrameworkServlet {
// Make framework objects available to handlers and view objects.
request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, getWebApplicationContext());
request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver);
request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver);
request.setAttribute(THEME_SOURCE_ATTRIBUTE, getThemeSource());
if (this.flashMapManager != null) {
FlashMap inputFlashMap = this.flashMapManager.retrieveAndUpdate(request, response);

View File

@ -1,70 +0,0 @@
/*
* Copyright 2002-2022 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
*
* https://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;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.jspecify.annotations.Nullable;
/**
* Interface for web-based theme resolution strategies that allows for
* both theme resolution via the request and theme modification via
* request and response.
*
* <p>This interface allows for implementations based on session,
* cookies, etc. The default implementation is
* {@link org.springframework.web.servlet.theme.FixedThemeResolver},
* simply using a configured default theme.
*
* <p>Note that this resolver is only responsible for determining the
* current theme name. The Theme instance for the resolved theme name
* gets looked up by DispatcherServlet via the respective ThemeSource,
* i.e. the current WebApplicationContext.
*
* <p>Use {@link org.springframework.web.servlet.support.RequestContext#getTheme()}
* to retrieve the current theme in controllers or views, independent
* of the actual resolution strategy.
*
* @author Jean-Pierre Pawlak
* @author Juergen Hoeller
* @since 17.06.2003
* @see org.springframework.ui.context.Theme
* @see org.springframework.ui.context.ThemeSource
* @deprecated as of 6.0 in favor of using CSS, without direct replacement
*/
@Deprecated(since = "6.0")
public interface ThemeResolver {
/**
* Resolve the current theme name via the given request.
* Should return a default theme as fallback in any case.
* @param request the request to be used for resolution
* @return the current theme name
*/
String resolveThemeName(HttpServletRequest request);
/**
* Set the current theme name to the given one.
* @param request the request to be used for theme name modification
* @param response the response to be used for theme name modification
* @param themeName the new theme name ({@code null} or empty to reset it)
* @throws UnsupportedOperationException if the ThemeResolver implementation
* does not support dynamic changing of the theme
*/
void setThemeName(HttpServletRequest request, @Nullable HttpServletResponse response, @Nullable String themeName);
}

View File

@ -81,7 +81,6 @@ public abstract class MvcNamespaceUtils {
registerSimpleControllerHandlerAdapter(context, source);
registerHandlerMappingIntrospector(context, source);
registerLocaleResolver(context, source);
registerThemeResolver(context, source);
registerViewNameTranslator(context, source);
registerFlashMapManager(context, source);
}
@ -306,21 +305,6 @@ public abstract class MvcNamespaceUtils {
}
}
/**
* Registers an {@link org.springframework.web.servlet.theme.FixedThemeResolver}
* under a well-known name unless already registered.
*/
@SuppressWarnings("deprecation")
private static void registerThemeResolver(ParserContext context, @Nullable Object source) {
if (!containsBeanInHierarchy(context, DispatcherServlet.THEME_RESOLVER_BEAN_NAME)) {
RootBeanDefinition beanDef = new RootBeanDefinition(org.springframework.web.servlet.theme.FixedThemeResolver.class);
beanDef.setSource(source);
beanDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
context.getRegistry().registerBeanDefinition(DispatcherServlet.THEME_RESOLVER_BEAN_NAME, beanDef);
context.registerComponent(new BeanComponentDefinition(beanDef, DispatcherServlet.THEME_RESOLVER_BEAN_NAME));
}
}
/**
* Registers an {@link DefaultRequestToViewNameTranslator} under a well-known name
* unless already registered.

View File

@ -1184,12 +1184,6 @@ public class WebMvcConfigurationSupport implements ApplicationContextAware, Serv
return new AcceptHeaderLocaleResolver();
}
@Bean
@Deprecated
public org.springframework.web.servlet.ThemeResolver themeResolver() {
return new org.springframework.web.servlet.theme.FixedThemeResolver();
}
@Bean
public FlashMapManager flashMapManager() {
return new SessionFlashMapManager();

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2024 the original author or authors.
* Copyright 2002-2025 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,16 +75,6 @@ import org.springframework.web.util.pattern.PathPatternParser;
*/
public class RequestContext {
/**
* Default theme name used if the RequestContext cannot find a ThemeResolver.
* Only applies to non-DispatcherServlet requests.
* <p>Same as AbstractThemeResolver's default, but not linked in here to avoid package interdependencies.
* @see org.springframework.web.servlet.theme.AbstractThemeResolver#ORIGINAL_DEFAULT_THEME_NAME
* @deprecated as of 6.0, with no direct replacement
*/
@Deprecated(since = "6.0")
public static final String DEFAULT_THEME_NAME = "theme";
/**
* Request attribute to hold the current web application context for RequestContext usage.
* By default, the DispatcherServlet's context (or the root context as fallback) is exposed.
@ -107,9 +97,6 @@ public class RequestContext {
private @Nullable TimeZone timeZone;
@Deprecated
private org.springframework.ui.context.@Nullable Theme theme;
private @Nullable Boolean defaultHtmlEscape;
private final @Nullable Boolean responseEncodedHtmlEscape;
@ -378,80 +365,6 @@ public class RequestContext {
this.timeZone = timeZone;
}
/**
* Return the current theme (never {@code null}).
* <p>Resolved lazily for more efficiency when theme support is not being used.
* @deprecated as of 6.0, with no direct replacement
*/
@Deprecated(since = "6.0")
public org.springframework.ui.context.Theme getTheme() {
if (this.theme == null) {
// Lazily determine theme to use for this RequestContext.
this.theme = RequestContextUtils.getTheme(this.request);
if (this.theme == null) {
// No ThemeResolver and ThemeSource available -> try fallback.
this.theme = getFallbackTheme();
}
}
return this.theme;
}
/**
* Determine the fallback theme for this context.
* <p>The default implementation returns the default theme (with name "theme").
* @return the fallback theme (never {@code null})
* @deprecated as of 6.0, with no direct replacement
*/
@Deprecated
protected org.springframework.ui.context.Theme getFallbackTheme() {
org.springframework.ui.context.ThemeSource themeSource = RequestContextUtils.getThemeSource(getRequest());
if (themeSource == null) {
themeSource = new org.springframework.ui.context.support.ResourceBundleThemeSource();
}
org.springframework.ui.context.Theme theme = themeSource.getTheme(DEFAULT_THEME_NAME);
if (theme == null) {
throw new IllegalStateException("No theme defined and no fallback theme found");
}
return theme;
}
/**
* Change the current theme to the specified one,
* storing the new theme name through the configured
* {@link org.springframework.web.servlet.ThemeResolver ThemeResolver}.
* @param theme the new theme
* @see org.springframework.web.servlet.ThemeResolver#setThemeName
* @deprecated as of 6.0, with no direct replacement
*/
@Deprecated(since = "6.0")
public void changeTheme(org.springframework.ui.context.@Nullable Theme theme) {
org.springframework.web.servlet.ThemeResolver themeResolver = RequestContextUtils.getThemeResolver(this.request);
if (themeResolver == null) {
throw new IllegalStateException("Cannot change theme if no ThemeResolver configured");
}
themeResolver.setThemeName(this.request, this.response, (theme != null ? theme.getName() : null));
this.theme = theme;
}
/**
* Change the current theme to the specified theme by name,
* storing the new theme name through the configured
* {@link org.springframework.web.servlet.ThemeResolver ThemeResolver}.
* @param themeName the name of the new theme
* @see org.springframework.web.servlet.ThemeResolver#setThemeName
* @deprecated as of 6.0, with no direct replacement
*/
@Deprecated
public void changeTheme(String themeName) {
org.springframework.web.servlet.ThemeResolver themeResolver = RequestContextUtils.getThemeResolver(this.request);
if (themeResolver == null) {
throw new IllegalStateException("Cannot change theme if no ThemeResolver configured");
}
themeResolver.setThemeName(this.request, this.response, themeName);
// Ask for re-resolution on next getTheme call.
this.theme = null;
}
/**
* (De)activate default HTML escaping for messages and errors, for the scope of this RequestContext.
* <p>The default is the application-wide setting (the "defaultHtmlEscape" context-param in web.xml).
@ -731,112 +644,6 @@ public class RequestContext {
return (htmlEscape ? HtmlUtils.htmlEscape(msg) : msg);
}
/**
* Retrieve the theme message for the given code.
* <p>Note that theme messages are never HTML-escaped, as they typically denote
* theme-specific resource paths and not client-visible messages.
* @param code the code of the message
* @param defaultMessage the String to return if the lookup fails
* @return the message
* @deprecated as of 6.0, with no direct replacement
*/
@Deprecated
public String getThemeMessage(String code, String defaultMessage) {
String msg = getTheme().getMessageSource().getMessage(code, null, defaultMessage, getLocale());
return (msg != null ? msg : "");
}
/**
* Retrieve the theme message for the given code.
* <p>Note that theme messages are never HTML-escaped, as they typically denote
* theme-specific resource paths and not client-visible messages.
* @param code the code of the message
* @param args arguments for the message, or {@code null} if none
* @param defaultMessage the String to return if the lookup fails
* @return the message
* @deprecated as of 6.0, with no direct replacement
*/
@Deprecated
public String getThemeMessage(String code, Object @Nullable [] args, String defaultMessage) {
String msg = getTheme().getMessageSource().getMessage(code, args, defaultMessage, getLocale());
return (msg != null ? msg : "");
}
/**
* Retrieve the theme message for the given code.
* <p>Note that theme messages are never HTML-escaped, as they typically denote
* theme-specific resource paths and not client-visible messages.
* @param code the code of the message
* @param args arguments for the message as a List, or {@code null} if none
* @param defaultMessage the String to return if the lookup fails
* @return the message
* @deprecated as of 6.0, with no direct replacement
*/
@Deprecated
public String getThemeMessage(String code, @Nullable List<?> args, String defaultMessage) {
String msg = getTheme().getMessageSource().getMessage(code, (args != null ? args.toArray() : null),
defaultMessage, getLocale());
return (msg != null ? msg : "");
}
/**
* Retrieve the theme message for the given code.
* <p>Note that theme messages are never HTML-escaped, as they typically denote
* theme-specific resource paths and not client-visible messages.
* @param code the code of the message
* @return the message
* @throws org.springframework.context.NoSuchMessageException if not found
* @deprecated as of 6.0, with no direct replacement
*/
@Deprecated
public String getThemeMessage(String code) throws NoSuchMessageException {
return getTheme().getMessageSource().getMessage(code, null, getLocale());
}
/**
* Retrieve the theme message for the given code.
* <p>Note that theme messages are never HTML-escaped, as they typically denote
* theme-specific resource paths and not client-visible messages.
* @param code the code of the message
* @param args arguments for the message, or {@code null} if none
* @return the message
* @throws org.springframework.context.NoSuchMessageException if not found
* @deprecated as of 6.0, with no direct replacement
*/
@Deprecated
public String getThemeMessage(String code, Object @Nullable [] args) throws NoSuchMessageException {
return getTheme().getMessageSource().getMessage(code, args, getLocale());
}
/**
* Retrieve the theme message for the given code.
* <p>Note that theme messages are never HTML-escaped, as they typically denote
* theme-specific resource paths and not client-visible messages.
* @param code the code of the message
* @param args arguments for the message as a List, or {@code null} if none
* @return the message
* @throws org.springframework.context.NoSuchMessageException if not found
* @deprecated as of 6.0, with no direct replacement
*/
@Deprecated
public String getThemeMessage(String code, @Nullable List<?> args) throws NoSuchMessageException {
return getTheme().getMessageSource().getMessage(code, (args != null ? args.toArray() : null), getLocale());
}
/**
* Retrieve the given MessageSourceResolvable in the current theme.
* <p>Note that theme messages are never HTML-escaped, as they typically denote
* theme-specific resource paths and not client-visible messages.
* @param resolvable the MessageSourceResolvable
* @return the message
* @throws org.springframework.context.NoSuchMessageException if not found
* @deprecated as of 6.0, with no direct replacement
*/
@Deprecated
public String getThemeMessage(MessageSourceResolvable resolvable) throws NoSuchMessageException {
return getTheme().getMessageSource().getMessage(resolvable, getLocale());
}
/**
* Retrieve the Errors instance for the given bind object, using the "defaultHtmlEscape" setting.
* @param name the name of the bind object

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 the original author or authors.
* Copyright 2002-2025 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.
@ -173,51 +173,6 @@ public abstract class RequestContextUtils {
return null;
}
/**
* Return the ThemeResolver that has been bound to the request by the
* DispatcherServlet.
* @param request current HTTP request
* @return the current ThemeResolver, or {@code null} if not found
* @deprecated as of 6.0, with no direct replacement
*/
@Deprecated(since = "6.0")
public static org.springframework.web.servlet.@Nullable ThemeResolver getThemeResolver(HttpServletRequest request) {
return (org.springframework.web.servlet.ThemeResolver) request.getAttribute(DispatcherServlet.THEME_RESOLVER_ATTRIBUTE);
}
/**
* Return the ThemeSource that has been bound to the request by the
* DispatcherServlet.
* @param request current HTTP request
* @return the current ThemeSource
* @deprecated as of 6.0, with no direct replacement
*/
@Deprecated(since = "6.0")
public static org.springframework.ui.context.@Nullable ThemeSource getThemeSource(HttpServletRequest request) {
return (org.springframework.ui.context.ThemeSource) request.getAttribute(DispatcherServlet.THEME_SOURCE_ATTRIBUTE);
}
/**
* Retrieve the current theme from the given request, using the ThemeResolver
* and ThemeSource bound to the request by the DispatcherServlet.
* @param request current HTTP request
* @return the current theme, or {@code null} if not found
* @see #getThemeResolver
* @deprecated as of 6.0, with no direct replacement
*/
@Deprecated(since = "6.0")
public static org.springframework.ui.context.@Nullable Theme getTheme(HttpServletRequest request) {
org.springframework.web.servlet.ThemeResolver themeResolver = getThemeResolver(request);
org.springframework.ui.context.ThemeSource themeSource = getThemeSource(request);
if (themeResolver != null && themeSource != null) {
String themeName = themeResolver.resolveThemeName(request);
return themeSource.getTheme(themeName);
}
else {
return null;
}
}
/**
* Return read-only "input" flash attributes from request before redirect.
* @param request current request

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2018 the original author or authors.
* Copyright 2002-2025 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.
@ -49,7 +49,6 @@ import org.jspecify.annotations.Nullable;
* @author Nicholas Williams
* @since 4.0
* @see MessageTag
* @see ThemeTag
*/
@SuppressWarnings("serial")
public class ArgumentTag extends BodyTagSupport {

View File

@ -1,147 +0,0 @@
/*
* Copyright 2002-2022 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
*
* https://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.tags;
import org.springframework.context.MessageSource;
import org.springframework.context.NoSuchMessageException;
/**
* The {@code <theme>} tag looks up a theme message in the scope of this page.
* Messages are looked up using the ApplicationContext's ThemeSource,
* and thus should support internationalization.
*
* <p>Regards an HTML escaping setting, either on this tag instance,
* the page level, or the web.xml level.
*
* <p>If "code" isn't set or cannot be resolved, "text" will be used
* as default message.
*
* <p>Message arguments can be specified via the {@link #setArguments(Object)
* arguments} attribute or by using nested {@code <spring:argument>} tags.
*
* <table>
* <caption>Attribute Summary</caption>
* <thead>
* <tr>
* <th>Attribute</th>
* <th>Required?</th>
* <th>Runtime Expression?</th>
* <th>Description</th>
* </tr>
* </thead>
* <tbody>
* <tr>
* <td>arguments</td>
* <td>false</td>
* <td>true</td>
* <td>Set optional message arguments for this tag, as a (comma-)delimited
* String (each String argument can contain JSP EL), an Object array (used as
* argument array), or a single Object (used as single argument).</td>
* </tr>
* <tr>
* <td>argumentSeparator</td>
* <td>false</td>
* <td>true</td>
* <td>The separator character to be used for splitting the arguments string
* value; defaults to a 'comma' (',').</td>
* </tr>
* <tr>
* <td>code</td>
* <td>false</td>
* <td>true</td>
* <td>The code (key) to use when looking up the message. If code is not
* provided, the text attribute will be used.</td>
* </tr>
* <tr>
* <td>htmlEscape</td>
* <td>false</td>
* <td>true</td>
* <td>Set HTML escaping for this tag, as boolean value. Overrides the default
* HTML escaping setting for the current page.</td>
* </tr>
* <tr>
* <td>javaScriptEscape</td>
* <td>false</td>
* <td>true</td>
* <td>Set JavaScript escaping for this tag, as boolean value.
* Default is {@code false}.</td>
* </tr>
* <tr>
* <td>message</td>
* <td>false</td>
* <td>true</td>
* <td>A MessageSourceResolvable argument (direct or through JSP EL).</td>
* </tr>
* <tr>
* <td>scope</td>
* <td>false</td>
* <td>true</td>
* <td>The scope to use when exporting the result to a variable. This attribute
* is only used when var is also set. Possible values are page, request, session
* and application.</td>
* </tr>
* <tr>
* <td>text</td>
* <td>false</td>
* <td>true</td>
* <td>Default text to output when a message for the given code could not be
* found. If both text and code are not set, the tag will output null.</td>
* </tr>
* <tr>
* <td>var</td>
* <td>false</td>
* <td>true</td>
* <td>The string to use when binding the result to the page, request, session
* or application scope. If not specified, the result gets outputted to the
* writer (i.e. typically directly to the JSP).</td>
* </tr>
* </tbody>
* </table>
*
* @author Jean-Pierre Pawlak
* @author Juergen Hoeller
* @see org.springframework.ui.context.Theme
* @see org.springframework.ui.context.ThemeSource
* @see #setCode
* @see #setText
* @see #setHtmlEscape
* @see HtmlEscapeTag#setDefaultHtmlEscape
* @see org.springframework.web.util.WebUtils#HTML_ESCAPE_CONTEXT_PARAM
* @see ArgumentTag
* @deprecated as of 6.0, with no direct replacement
*/
@SuppressWarnings("serial")
@Deprecated(since = "6.0")
public class ThemeTag extends MessageTag {
/**
* Use the theme MessageSource for theme message resolution.
*/
@Override
protected MessageSource getMessageSource() {
return getRequestContext().getTheme().getMessageSource();
}
/**
* Return exception message that indicates the current theme.
*/
@Override
protected String getNoSuchMessageExceptionDescription(NoSuchMessageException ex) {
return "Theme '" + getRequestContext().getTheme().getName() + "': " + ex.getMessage();
}
}

View File

@ -14,7 +14,6 @@
* <li>{@link org.springframework.web.servlet.tags.MessageTag The message tag}
* <li>{@link org.springframework.web.servlet.tags.NestedPathTag The nestedPath tag}
* <li>{@link org.springframework.web.servlet.tags.ParamTag The param tag}
* <li>{@link org.springframework.web.servlet.tags.ThemeTag The theme tag}
* <li>{@link org.springframework.web.servlet.tags.TransformTag The transform tag}
* <li>{@link org.springframework.web.servlet.tags.UrlTag The url tag}
* </ul>

View File

@ -1,56 +0,0 @@
/*
* Copyright 2002-2022 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
*
* https://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.theme;
import org.springframework.web.servlet.ThemeResolver;
/**
* Abstract base class for {@link ThemeResolver} implementations.
* Provides support for a default theme name.
*
* @author Juergen Hoeller
* @author Jean-Pierre Pawlak
* @since 17.06.2003
* @deprecated as of 6.0 in favor of using CSS, without direct replacement
*/
@Deprecated(since = "6.0")
public abstract class AbstractThemeResolver implements ThemeResolver {
/**
* Out-of-the-box value for the default theme name: "theme".
*/
public static final String ORIGINAL_DEFAULT_THEME_NAME = "theme";
private String defaultThemeName = ORIGINAL_DEFAULT_THEME_NAME;
/**
* Set the name of the default theme.
* Out-of-the-box value is "theme".
*/
public void setDefaultThemeName(String defaultThemeName) {
this.defaultThemeName = defaultThemeName;
}
/**
* Return the name of the default theme.
*/
public String getDefaultThemeName() {
return this.defaultThemeName;
}
}

View File

@ -1,137 +0,0 @@
/*
* Copyright 2002-2022 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
*
* https://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.theme;
import jakarta.servlet.http.Cookie;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.jspecify.annotations.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
import org.springframework.web.servlet.ThemeResolver;
import org.springframework.web.util.CookieGenerator;
import org.springframework.web.util.WebUtils;
/**
* {@link ThemeResolver} implementation that uses a cookie sent back to the user
* in case of a custom setting, with a fallback to the default theme.
* This is particularly useful for stateless applications without user sessions.
*
* <p>Custom controllers can thus override the user's theme by calling
* {@code setThemeName}, for example, responding to a certain theme change request.
*
* @author Jean-Pierre Pawlak
* @author Juergen Hoeller
* @since 17.06.2003
* @see #setThemeName
* @deprecated as of 6.0 in favor of using CSS, without direct replacement for removal in 7.1
*/
@Deprecated(since = "6.0", forRemoval = true)
@SuppressWarnings("removal")
public class CookieThemeResolver extends CookieGenerator implements ThemeResolver {
/**
* The default theme name used if no alternative is provided.
*/
public static final String ORIGINAL_DEFAULT_THEME_NAME = "theme";
/**
* Name of the request attribute that holds the theme name. Only used
* for overriding a cookie value if the theme has been changed in the
* course of the current request! Use RequestContext.getTheme() to
* retrieve the current theme in controllers or views.
* @see org.springframework.web.servlet.support.RequestContext#getTheme
*/
public static final String THEME_REQUEST_ATTRIBUTE_NAME = CookieThemeResolver.class.getName() + ".THEME";
/**
* The default name of the cookie that holds the theme name.
*/
public static final String DEFAULT_COOKIE_NAME = CookieThemeResolver.class.getName() + ".THEME";
private String defaultThemeName = ORIGINAL_DEFAULT_THEME_NAME;
public CookieThemeResolver() {
setCookieName(DEFAULT_COOKIE_NAME);
}
/**
* Set the name of the default theme.
*/
public void setDefaultThemeName(String defaultThemeName) {
this.defaultThemeName = defaultThemeName;
}
/**
* Return the name of the default theme.
*/
public String getDefaultThemeName() {
return this.defaultThemeName;
}
@Override
public String resolveThemeName(HttpServletRequest request) {
// Check request for preparsed or preset theme.
String themeName = (String) request.getAttribute(THEME_REQUEST_ATTRIBUTE_NAME);
if (themeName != null) {
return themeName;
}
// Retrieve cookie value from request.
String cookieName = getCookieName();
if (cookieName != null) {
Cookie cookie = WebUtils.getCookie(request, cookieName);
if (cookie != null) {
String value = cookie.getValue();
if (StringUtils.hasText(value)) {
themeName = value;
}
}
}
// Fall back to default theme.
if (themeName == null) {
themeName = getDefaultThemeName();
}
request.setAttribute(THEME_REQUEST_ATTRIBUTE_NAME, themeName);
return themeName;
}
@Override
public void setThemeName(
HttpServletRequest request, @Nullable HttpServletResponse response, @Nullable String themeName) {
Assert.notNull(response, "HttpServletResponse is required for CookieThemeResolver");
if (StringUtils.hasText(themeName)) {
// Set request attribute and add cookie.
request.setAttribute(THEME_REQUEST_ATTRIBUTE_NAME, themeName);
addCookie(response, themeName);
}
else {
// Set request attribute to fallback theme and remove cookie.
request.setAttribute(THEME_REQUEST_ATTRIBUTE_NAME, getDefaultThemeName());
removeCookie(response);
}
}
}

View File

@ -1,52 +0,0 @@
/*
* Copyright 2002-2022 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
*
* https://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.theme;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.jspecify.annotations.Nullable;
/**
* {@link org.springframework.web.servlet.ThemeResolver} implementation
* that simply uses a fixed theme. The fixed name can be defined via
* the "defaultThemeName" property; out of the box, it is "theme".
*
* <p>Note: Does not support {@code setThemeName}, as the fixed theme
* cannot be changed.
*
* @author Jean-Pierre Pawlak
* @author Juergen Hoeller
* @since 17.06.2003
* @see #setDefaultThemeName
* @deprecated as of 6.0 in favor of using CSS, without direct replacement
*/
@Deprecated(since = "6.0")
public class FixedThemeResolver extends AbstractThemeResolver {
@Override
public String resolveThemeName(HttpServletRequest request) {
return getDefaultThemeName();
}
@Override
public void setThemeName(
HttpServletRequest request, @Nullable HttpServletResponse response, @Nullable String themeName) {
throw new UnsupportedOperationException("Cannot change theme - use a different theme resolution strategy");
}
}

View File

@ -1,70 +0,0 @@
/*
* Copyright 2002-2022 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
*
* https://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.theme;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.jspecify.annotations.Nullable;
import org.springframework.util.StringUtils;
import org.springframework.web.util.WebUtils;
/**
* {@link org.springframework.web.servlet.ThemeResolver} implementation that
* uses a theme attribute in the user's session in case of a custom setting,
* with a fallback to the default theme. This is most appropriate if the
* application needs user sessions anyway.
*
* <p>Custom controllers can override the user's theme by calling
* {@code setThemeName}, for example, responding to a theme change request.
*
* @author Jean-Pierre Pawlak
* @author Juergen Hoeller
* @since 17.06.2003
* @see #setThemeName
* @deprecated as of 6.0 in favor of using CSS, without direct replacement
*/
@Deprecated(since = "6.0")
public class SessionThemeResolver extends AbstractThemeResolver {
/**
* Name of the session attribute that holds the theme name.
* Only used internally by this implementation.
* Use {@code RequestContext(Utils).getTheme()}
* to retrieve the current theme in controllers or views.
* @see org.springframework.web.servlet.support.RequestContext#getTheme
* @see org.springframework.web.servlet.support.RequestContextUtils#getTheme
*/
public static final String THEME_SESSION_ATTRIBUTE_NAME = SessionThemeResolver.class.getName() + ".THEME";
@Override
public String resolveThemeName(HttpServletRequest request) {
String themeName = (String) WebUtils.getSessionAttribute(request, THEME_SESSION_ATTRIBUTE_NAME);
// A specific theme indicated, or do we need to fall back to the default?
return (themeName != null ? themeName : getDefaultThemeName());
}
@Override
public void setThemeName(
HttpServletRequest request, @Nullable HttpServletResponse response, @Nullable String themeName) {
WebUtils.setSessionAttribute(request, THEME_SESSION_ATTRIBUTE_NAME,
(StringUtils.hasText(themeName) ? themeName : null));
}
}

View File

@ -1,80 +0,0 @@
/*
* Copyright 2002-2022 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
*
* https://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.theme;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ThemeResolver;
import org.springframework.web.servlet.support.RequestContextUtils;
/**
* Interceptor that allows for changing the current theme on every request,
* via a configurable request parameter (default parameter name: "theme").
*
* @author Juergen Hoeller
* @since 20.06.2003
* @see org.springframework.web.servlet.ThemeResolver
* @deprecated as of 6.0 in favor of using CSS, without direct replacement
*/
@Deprecated(since = "6.0")
public class ThemeChangeInterceptor implements HandlerInterceptor {
/**
* Default name of the theme specification parameter: "theme".
*/
public static final String DEFAULT_PARAM_NAME = "theme";
private String paramName = DEFAULT_PARAM_NAME;
/**
* Set the name of the parameter that contains a theme specification
* in a theme change request. Default is "theme".
*/
public void setParamName(String paramName) {
this.paramName = paramName;
}
/**
* Return the name of the parameter that contains a theme specification
* in a theme change request.
*/
public String getParamName() {
return this.paramName;
}
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws ServletException {
String newTheme = request.getParameter(this.paramName);
if (newTheme != null) {
ThemeResolver themeResolver = RequestContextUtils.getThemeResolver(request);
if (themeResolver == null) {
throw new IllegalStateException("No ThemeResolver found: not in a DispatcherServlet request?");
}
themeResolver.setThemeName(request, response, newTheme);
}
// Proceed in any case.
return true;
}
}

View File

@ -1,23 +0,0 @@
/**
* Theme support classes for Spring's web MVC framework.
* Provides standard ThemeResolver implementations,
* and a HandlerInterceptor for theme changes.
*
* <p>
* <ul>
* <li>If you don't provide a bean of one of these classes as {@code themeResolver},
* a {@code FixedThemeResolver} will be provided with the default theme name 'theme'.</li>
* <li>If you use a defined {@code FixedThemeResolver}, you will able to use another theme
* name for default, but the users will stick on this theme.</li>
* <li>With a {@code CookieThemeResolver} or {@code SessionThemeResolver}, you can allow
* the user to change his current theme.</li>
* <li>Generally, you will put in the themes resource bundles the paths of CSS files, images and HTML constructs.</li>
* <li>For retrieving themes data, you can either use the spring:theme tag in JSP or access via the
* {@code RequestContext} for other view technologies.</li>
* <li>The {@code pagedlist} demo application uses themes</li>
* </ul>
*/
@NullMarked
package org.springframework.web.servlet.theme;
import org.jspecify.annotations.NullMarked;

View File

@ -128,82 +128,6 @@
</attribute>
</tag>
<tag>
<description>Retrieves the theme message with the given code, or text if code isn't
resolvable. The HTML escaping flag participates in a page-wide or application-wide setting
(i.e. by HtmlEscapeTag or a "defaultHtmlEscape" context-param in web.xml).</description>
<name>theme</name>
<tag-class>org.springframework.web.servlet.tags.ThemeTag</tag-class>
<body-content>JSP</body-content>
<attribute>
<description>A MessageSourceResolvable argument (direct or through JSP EL).</description>
<name>message</name>
<required>false</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
<attribute>
<description>The code (key) to use when looking up the message.
If code is not provided, the text attribute will be used.</description>
<name>code</name>
<required>false</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
<attribute>
<description>Set optional message arguments for this tag, as a (comma-)
delimited String (each String argument can contain JSP EL), an Object array
(used as argument array), or a single Object (used as single argument).
You can additionally use nested spring:argument tags.</description>
<name>arguments</name>
<required>false</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
<attribute>
<description>The separator character to be used for splitting the
arguments string value; defaults to a 'comma' (',').</description>
<name>argumentSeparator</name>
<required>false</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
<attribute>
<description>Default text to output when a message for the given code
could not be found. If both text and code are not set, the tag will
output null.</description>
<name>text</name>
<required>false</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
<attribute>
<description>The string to use when binding the result to the page,
request, session or application scope. If not specified, the result
gets outputted to the writer (i.e. typically directly to the JSP).</description>
<name>var</name>
<required>false</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
<attribute>
<description>The scope to use when exporting the result to a variable.
This attribute is only used when var is also set. Possible values are
page, request, session and application.</description>
<name>scope</name>
<required>false</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
<attribute>
<description>Set HTML escaping for this tag, as boolean value.
Overrides the default HTML escaping setting for the current page.</description>
<name>htmlEscape</name>
<required>false</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
<attribute>
<description>Set JavaScript escaping for this tag, as boolean value.
Default is 'false'.</description>
<name>javaScriptEscape</name>
<required>false</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
</tag>
<tag>
<description>Argument tag based on the JSTL fmt:param tag. The purpose is to
support arguments inside the spring:message and spring:theme tags.</description>

View File

@ -4,8 +4,6 @@
org.springframework.web.servlet.LocaleResolver=org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver
org.springframework.web.servlet.ThemeResolver=org.springframework.web.servlet.theme.FixedThemeResolver
org.springframework.web.servlet.HandlerMapping=org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping,\
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping,\
org.springframework.web.servlet.function.support.RouterFunctionMapping

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2024 the original author or authors.
* Copyright 2002-2025 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.
@ -95,7 +95,7 @@ class XmlWebApplicationContextTests extends AbstractApplicationContextTests {
@Test
@Override
protected void count() {
assertThat(this.applicationContext.getBeanDefinitionCount()).as("should have 14 beans").isEqualTo(14);
assertThat(this.applicationContext.getBeanDefinitionCount()).as("should have 14 beans").isEqualTo(13);
}
@Test

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2024 the original author or authors.
* Copyright 2002-2025 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.
@ -74,29 +74,19 @@ import org.springframework.web.util.WebUtils;
public class ComplexWebApplicationContext extends StaticWebApplicationContext {
@Override
@SuppressWarnings("deprecation")
public void refresh() throws BeansException {
registerSingleton(DispatcherServlet.LOCALE_RESOLVER_BEAN_NAME, SessionLocaleResolver.class);
registerSingleton(DispatcherServlet.THEME_RESOLVER_BEAN_NAME,
org.springframework.web.servlet.theme.SessionThemeResolver.class);
LocaleChangeInterceptor interceptor1 = new LocaleChangeInterceptor();
LocaleChangeInterceptor interceptor2 = new LocaleChangeInterceptor();
interceptor2.setParamName("locale2");
org.springframework.web.servlet.theme.ThemeChangeInterceptor interceptor3 =
new org.springframework.web.servlet.theme.ThemeChangeInterceptor();
org.springframework.web.servlet.theme.ThemeChangeInterceptor interceptor4 =
new org.springframework.web.servlet.theme.ThemeChangeInterceptor();
interceptor4.setParamName("theme2");
UserRoleAuthorizationInterceptor interceptor5 = new UserRoleAuthorizationInterceptor();
interceptor5.setAuthorizedRoles("role1", "role2");
UserRoleAuthorizationInterceptor interceptor3 = new UserRoleAuthorizationInterceptor();
interceptor3.setAuthorizedRoles("role1", "role2");
List<Object> interceptors = new ArrayList<>();
interceptors.add(interceptor5);
interceptors.add(interceptor3);
interceptors.add(interceptor1);
interceptors.add(interceptor2);
interceptors.add(interceptor3);
interceptors.add(interceptor4);
interceptors.add(new MyHandlerInterceptor1());
interceptors.add(new MyHandlerInterceptor2());
interceptors.add(new MyWebRequestInterceptor());
@ -457,16 +447,8 @@ public class ComplexWebApplicationContext extends StaticWebApplicationContext {
if (!TimeZone.getDefault().equals(LocaleContextHolder.getTimeZone())) {
throw new ServletException("Incorrect TimeZone");
}
if (!(RequestContextUtils.getThemeResolver(request)
instanceof org.springframework.web.servlet.theme.SessionThemeResolver)) {
throw new ServletException("Incorrect ThemeResolver");
}
if (!"theme".equals(RequestContextUtils.getThemeResolver(request).resolveThemeName(request))) {
throw new ServletException("Incorrect theme name");
}
RequestContext rc = new RequestContext(request);
rc.changeLocale(Locale.US, TimeZone.getTimeZone("GMT+1"));
rc.changeTheme("theme2");
if (!Locale.US.equals(RequestContextUtils.getLocale(request))) {
throw new ServletException("Incorrect Locale");
}
@ -479,9 +461,6 @@ public class ComplexWebApplicationContext extends StaticWebApplicationContext {
if (!TimeZone.getTimeZone("GMT+1").equals(LocaleContextHolder.getTimeZone())) {
throw new ServletException("Incorrect TimeZone");
}
if (!"theme2".equals(RequestContextUtils.getThemeResolver(request).resolveThemeName(request))) {
throw new ServletException("Incorrect theme name");
}
}
@Override

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2024 the original author or authors.
* Copyright 2002-2025 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.
@ -396,31 +396,6 @@ class DispatcherServletTests {
assertThat(response.getForwardedUrl()).as("Not forwarded").isNull();
}
@Test
void themeChangeInterceptor1() throws Exception {
MockHttpServletRequest request = new MockHttpServletRequest(getServletContext(), "GET", "/locale.do");
request.addPreferredLocale(Locale.CANADA);
request.addUserRole("role1");
request.addParameter("theme", "mytheme");
MockHttpServletResponse response = new MockHttpServletResponse();
complexDispatcherServlet.service(request, response);
assertThat(response.getStatus()).isEqualTo(200);
assertThat(response.getForwardedUrl()).as("forwarded URL").isEqualTo("failed0.jsp");
assertThat(request.getAttribute("exception").getClass().equals(ServletException.class)).as("Exception exposed").isTrue();
}
@Test
void themeChangeInterceptor2() throws Exception {
MockHttpServletRequest request = new MockHttpServletRequest(getServletContext(), "GET", "/locale.do");
request.addPreferredLocale(Locale.CANADA);
request.addUserRole("role1");
request.addParameter("theme", "mytheme");
request.addParameter("theme2", "theme");
MockHttpServletResponse response = new MockHttpServletResponse();
complexDispatcherServlet.service(request, response);
assertThat(response.getForwardedUrl()).as("Not forwarded").isNull();
}
@Test
void notAuthorized() throws Exception {
MockHttpServletRequest request = new MockHttpServletRequest(getServletContext(), "GET", "/locale.do");

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2024 the original author or authors.
* Copyright 2002-2025 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,17 +25,11 @@ import jakarta.servlet.http.HttpServletResponse;
import org.springframework.beans.BeansException;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.context.support.StaticMessageSource;
import org.springframework.ui.context.Theme;
import org.springframework.ui.context.ThemeSource;
import org.springframework.ui.context.support.SimpleTheme;
import org.springframework.ui.context.support.UiApplicationContextUtils;
import org.springframework.web.context.support.StaticWebApplicationContext;
import org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping;
import org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver;
import org.springframework.web.servlet.mvc.Controller;
import org.springframework.web.servlet.support.RequestContextUtils;
import org.springframework.web.servlet.theme.AbstractThemeResolver;
import org.springframework.web.servlet.view.InternalResourceViewResolver;
/**
@ -54,8 +48,6 @@ public class SimpleWebApplicationContext extends StaticWebApplicationContext {
addMessage("testArgs", Locale.ENGLISH, "test {0} message {1}");
addMessage("testArgsFormat", Locale.ENGLISH, "test {0} message {1,number,#.##} X");
registerSingleton(UiApplicationContextUtils.THEME_SOURCE_BEAN_NAME, DummyThemeSource.class);
registerSingleton("handlerMapping", BeanNameUrlHandlerMapping.class);
registerSingleton("viewResolver", InternalResourceViewResolver.class);
@ -91,26 +83,4 @@ public class SimpleWebApplicationContext extends StaticWebApplicationContext {
}
}
public static class DummyThemeSource implements ThemeSource {
private final StaticMessageSource messageSource;
public DummyThemeSource() {
this.messageSource = new StaticMessageSource();
this.messageSource.addMessage("themetest", Locale.ENGLISH, "theme test message");
this.messageSource.addMessage("themetestArgs", Locale.ENGLISH, "theme test message {0}");
}
@Override
public Theme getTheme(String themeName) {
if (AbstractThemeResolver.ORIGINAL_DEFAULT_THEME_NAME.equals(themeName)) {
return new SimpleTheme(AbstractThemeResolver.ORIGINAL_DEFAULT_THEME_NAME, this.messageSource);
}
else {
return null;
}
}
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2024 the original author or authors.
* Copyright 2002-2025 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.
@ -50,7 +50,6 @@ import org.springframework.web.servlet.mvc.method.annotation.ServletWebArgumentR
import org.springframework.web.util.UrlPathHelper;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.InstanceOfAssertFactories.BOOLEAN;
/**
* Test fixture for the configuration in mvc-config-annotation-driven.xml.
@ -74,8 +73,6 @@ class AnnotationDrivenBeanDefinitionParserTests {
((ConfigurableWebBindingInitializer) initializer).getMessageCodesResolver();
assertThat(resolver).isNotNull();
assertThat(resolver.getClass()).isEqualTo(TestMessageCodesResolver.class);
assertThat(new DirectFieldAccessor(adapter).getPropertyValue("ignoreDefaultModelOnRedirect"))
.asInstanceOf(BOOLEAN).isTrue();
}
@SuppressWarnings("removal")

View File

@ -91,7 +91,6 @@ import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.LocaleResolver;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.RequestToViewNameTranslator;
import org.springframework.web.servlet.ThemeResolver;
import org.springframework.web.servlet.ViewResolver;
import org.springframework.web.servlet.handler.AbstractHandlerMapping;
import org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping;
@ -125,8 +124,6 @@ import org.springframework.web.servlet.resource.ResourceUrlProvider;
import org.springframework.web.servlet.resource.ResourceUrlProviderExposingInterceptor;
import org.springframework.web.servlet.resource.VersionResourceResolver;
import org.springframework.web.servlet.support.SessionFlashMapManager;
import org.springframework.web.servlet.theme.CookieThemeResolver;
import org.springframework.web.servlet.theme.ThemeChangeInterceptor;
import org.springframework.web.servlet.view.BeanNameViewResolver;
import org.springframework.web.servlet.view.ContentNegotiatingViewResolver;
import org.springframework.web.servlet.view.DefaultRequestToViewNameTranslator;
@ -151,7 +148,6 @@ import org.springframework.web.util.pattern.PathPatternParser;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.assertj.core.api.InstanceOfAssertFactories.BOOLEAN;
/**
* Tests loading actual MVC namespace configuration.
@ -218,8 +214,6 @@ public class MvcNamespaceTests {
RequestMappingHandlerAdapter adapter = appContext.getBean(RequestMappingHandlerAdapter.class);
assertThat(adapter).isNotNull();
assertThat(new DirectFieldAccessor(adapter).getPropertyValue("ignoreDefaultModelOnRedirect"))
.asInstanceOf(BOOLEAN).isTrue();
List<HttpMessageConverter<?>> converters = adapter.getMessageConverters();
assertThat(converters.size()).isGreaterThan(0);
@ -240,7 +234,6 @@ public class MvcNamespaceTests {
assertThat(appContext.getBean(LocalValidatorFactoryBean.class)).isNotNull();
assertThat(appContext.getBean(Validator.class)).isNotNull();
assertThat(appContext.getBean("localeResolver", LocaleResolver.class)).isNotNull();
assertThat(appContext.getBean("themeResolver", ThemeResolver.class)).isNotNull();
assertThat(appContext.getBean("viewNameTranslator", RequestToViewNameTranslator.class)).isNotNull();
assertThat(appContext.getBean("flashMapManager", FlashMapManager.class)).isNotNull();
@ -277,11 +270,9 @@ public class MvcNamespaceTests {
}
@Test // gh-25290
@SuppressWarnings("removal")
void testDefaultConfigWithBeansInParentContext() {
StaticApplicationContext parent = new StaticApplicationContext();
parent.registerSingleton("localeResolver", CookieLocaleResolver.class);
parent.registerSingleton("themeResolver", CookieThemeResolver.class);
parent.registerSingleton("viewNameTranslator", DefaultRequestToViewNameTranslator.class);
parent.registerSingleton("flashMapManager", SessionFlashMapManager.class);
parent.refresh();
@ -289,7 +280,6 @@ public class MvcNamespaceTests {
loadBeanDefinitions("mvc-config.xml");
assertThat(appContext.getBean("localeResolver")).isSameAs(parent.getBean("localeResolver"));
assertThat(appContext.getBean("themeResolver")).isSameAs(parent.getBean("themeResolver"));
assertThat(appContext.getBean("viewNameTranslator")).isSameAs(parent.getBean("viewNameTranslator"));
assertThat(appContext.getBean("flashMapManager")).isSameAs(parent.getBean("flashMapManager"));
}
@ -326,7 +316,6 @@ public class MvcNamespaceTests {
doTestCustomValidator("mvc-config-custom-validator.xml");
}
@SuppressWarnings("removal")
private void doTestCustomValidator(String xml) throws Exception {
loadBeanDefinitions(xml);
@ -336,7 +325,6 @@ public class MvcNamespaceTests {
RequestMappingHandlerAdapter adapter = appContext.getBean(RequestMappingHandlerAdapter.class);
assertThat(adapter).isNotNull();
assertThat(new DirectFieldAccessor(adapter).getPropertyValue("ignoreDefaultModelOnRedirect")).asInstanceOf(BOOLEAN).isTrue();
// default web binding initializer behavior test
MockHttpServletRequest request = new MockHttpServletRequest();
@ -359,14 +347,12 @@ public class MvcNamespaceTests {
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/");
request.setRequestURI("/accounts/12345");
request.addParameter("locale", "en");
request.addParameter("theme", "green");
HandlerExecutionChain chain = mapping.getHandler(request);
assertThat(chain.getInterceptorList()).hasSize(4);
assertThat(chain.getInterceptorList()).hasSize(3);
assertThat(chain.getInterceptorList()).element(0).isInstanceOf(ConversionServiceExposingInterceptor.class);
assertThat(chain.getInterceptorList()).element(1).isInstanceOf(LocaleChangeInterceptor.class);
assertThat(chain.getInterceptorList()).element(2).isInstanceOf(ThemeChangeInterceptor.class);
assertThat(chain.getInterceptorList()).element(3).isInstanceOf(UserRoleAuthorizationInterceptor.class);
assertThat(chain.getInterceptorList()).element(2).isInstanceOf(UserRoleAuthorizationInterceptor.class);
request.setRequestURI("/admin/users");
chain = mapping.getHandler(request);
@ -374,11 +360,11 @@ public class MvcNamespaceTests {
request.setRequestURI("/logged/accounts/12345");
chain = mapping.getHandler(request);
assertThat(chain.getInterceptorList()).hasSize(3);
assertThat(chain.getInterceptorList()).hasSize(2);
request.setRequestURI("/foo/logged");
chain = mapping.getHandler(request);
assertThat(chain.getInterceptorList()).hasSize(3);
assertThat(chain.getInterceptorList()).hasSize(2);
}
@Test
@ -608,14 +594,11 @@ public class MvcNamespaceTests {
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/");
HandlerExecutionChain chain = mapping.getHandler(request);
assertThat(chain.getInterceptorList()).hasSize(3);
assertThat(chain.getInterceptorList()).hasSize(2);
assertThat(chain.getInterceptorList()).element(0).isInstanceOf(ConversionServiceExposingInterceptor.class);
assertThat(chain.getInterceptorList()).element(1).isInstanceOf(LocaleChangeInterceptor.class);
assertThat(chain.getInterceptorList()).element(2).isInstanceOf(ThemeChangeInterceptor.class);
LocaleChangeInterceptor interceptor = (LocaleChangeInterceptor) chain.getInterceptorList().get(1);
assertThat(interceptor.getParamName()).isEqualTo("lang");
ThemeChangeInterceptor interceptor2 = (ThemeChangeInterceptor) chain.getInterceptorList().get(2);
assertThat(interceptor2.getParamName()).isEqualTo("style");
}
@Test
@ -638,10 +621,9 @@ public class MvcNamespaceTests {
request.setMethod("GET");
HandlerExecutionChain chain = mapping.getHandler(request);
assertThat(chain.getInterceptorList()).hasSize(3);
assertThat(chain.getInterceptorList()).hasSize(2);
assertThat(chain.getInterceptorList()).element(0).isInstanceOf(ConversionServiceExposingInterceptor.class);
assertThat(chain.getInterceptorList()).element(1).isInstanceOf(LocaleChangeInterceptor.class);
assertThat(chain.getInterceptorList()).element(2).isInstanceOf(ThemeChangeInterceptor.class);
SimpleUrlHandlerMapping mapping2 = appContext.getBean(SimpleUrlHandlerMapping.class);
assertThat(mapping2).isNotNull();
@ -651,10 +633,9 @@ public class MvcNamespaceTests {
request = new MockHttpServletRequest("GET", "/foo");
chain = mapping2.getHandler(request);
assertThat(chain.getInterceptorList()).hasSize(4);
assertThat(chain.getInterceptorList()).hasSize(3);
assertThat(chain.getInterceptorList()).element(1).isInstanceOf(ConversionServiceExposingInterceptor.class);
assertThat(chain.getInterceptorList()).element(2).isInstanceOf(LocaleChangeInterceptor.class);
assertThat(chain.getInterceptorList()).element(3).isInstanceOf(ThemeChangeInterceptor.class);
ModelAndView mv = adapter.handle(request, new MockHttpServletResponse(), chain.getHandler());
assertThat(mv.getViewName()).isNull();
@ -662,10 +643,9 @@ public class MvcNamespaceTests {
request.setContextPath("/myapp");
request.setServletPath("/app");
chain = mapping2.getHandler(request);
assertThat(chain.getInterceptorList()).hasSize(4);
assertThat(chain.getInterceptorList()).hasSize(3);
assertThat(chain.getInterceptorList()).element(1).isInstanceOf(ConversionServiceExposingInterceptor.class);
assertThat(chain.getInterceptorList()).element(2).isInstanceOf(LocaleChangeInterceptor.class);
assertThat(chain.getInterceptorList()).element(3).isInstanceOf(ThemeChangeInterceptor.class);
mv = adapter.handle(request, new MockHttpServletResponse(), chain.getHandler());
assertThat(mv.getViewName()).isEqualTo("baz");
@ -673,10 +653,9 @@ public class MvcNamespaceTests {
request.setContextPath("/myapp");
request.setServletPath("/app");
chain = mapping2.getHandler(request);
assertThat(chain.getInterceptorList()).hasSize(4);
assertThat(chain.getInterceptorList()).hasSize(3);
assertThat(chain.getInterceptorList()).element(1).isInstanceOf(ConversionServiceExposingInterceptor.class);
assertThat(chain.getInterceptorList()).element(2).isInstanceOf(LocaleChangeInterceptor.class);
assertThat(chain.getInterceptorList()).element(3).isInstanceOf(ThemeChangeInterceptor.class);
mv = adapter.handle(request, new MockHttpServletResponse(), chain.getHandler());
assertThat(mv.getViewName()).isEqualTo("root");
@ -717,10 +696,9 @@ public class MvcNamespaceTests {
request.setServletPath("/app/");
request.setAttribute("com.ibm.websphere.servlet.uri_non_decoded", "/myapp/app/bar");
HandlerExecutionChain chain = mapping2.getHandler(request);
assertThat(chain.getInterceptorList()).hasSize(4);
assertThat(chain.getInterceptorList()).hasSize(3);
assertThat(chain.getInterceptorList()).element(1).isInstanceOf(ConversionServiceExposingInterceptor.class);
assertThat(chain.getInterceptorList()).element(2).isInstanceOf(LocaleChangeInterceptor.class);
assertThat(chain.getInterceptorList()).element(3).isInstanceOf(ThemeChangeInterceptor.class);
ModelAndView mv2 = adapter.handle(request, new MockHttpServletResponse(), chain.getHandler());
assertThat(mv2.getViewName()).isEqualTo("baz");
@ -729,10 +707,9 @@ public class MvcNamespaceTests {
request.setServletPath("/app/");
request.setHttpServletMapping(new MockHttpServletMapping("", "", "", MappingMatch.PATH));
chain = mapping2.getHandler(request);
assertThat(chain.getInterceptorList()).hasSize(4);
assertThat(chain.getInterceptorList()).hasSize(3);
assertThat(chain.getInterceptorList()).element(1).isInstanceOf(ConversionServiceExposingInterceptor.class);
assertThat(chain.getInterceptorList()).element(2).isInstanceOf(LocaleChangeInterceptor.class);
assertThat(chain.getInterceptorList()).element(3).isInstanceOf(ThemeChangeInterceptor.class);
ModelAndView mv3 = adapter.handle(request, new MockHttpServletResponse(), chain.getHandler());
assertThat(mv3.getViewName()).isEqualTo("root");
@ -740,10 +717,9 @@ public class MvcNamespaceTests {
request.setContextPath("/myapp");
request.setServletPath("/");
chain = mapping2.getHandler(request);
assertThat(chain.getInterceptorList()).hasSize(4);
assertThat(chain.getInterceptorList()).hasSize(3);
assertThat(chain.getInterceptorList()).element(1).isInstanceOf(ConversionServiceExposingInterceptor.class);
assertThat(chain.getInterceptorList()).element(2).isInstanceOf(LocaleChangeInterceptor.class);
assertThat(chain.getInterceptorList()).element(3).isInstanceOf(ThemeChangeInterceptor.class);
mv3 = adapter.handle(request, new MockHttpServletResponse(), chain.getHandler());
assertThat(mv3.getViewName()).isEqualTo("root");
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2024 the original author or authors.
* Copyright 2002-2025 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,7 +35,6 @@ import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.handler.MappedInterceptor;
import org.springframework.web.servlet.handler.WebRequestHandlerInterceptorAdapter;
import org.springframework.web.servlet.i18n.LocaleChangeInterceptor;
import org.springframework.web.servlet.theme.ThemeChangeInterceptor;
import org.springframework.web.testfixture.servlet.MockHttpServletRequest;
import org.springframework.web.testfixture.servlet.MockHttpServletResponse;
@ -57,7 +56,7 @@ public class InterceptorRegistryTests {
private final HandlerInterceptor interceptor1 = new LocaleChangeInterceptor();
private final HandlerInterceptor interceptor2 = new ThemeChangeInterceptor();
private final HandlerInterceptor interceptor2 = new LocaleChangeInterceptor();
private TestWebRequestInterceptor webInterceptor1;

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2024 the original author or authors.
* Copyright 2002-2025 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.
@ -87,7 +87,6 @@ import org.springframework.web.util.UrlPathHelper;
import static com.fasterxml.jackson.databind.DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES;
import static com.fasterxml.jackson.databind.MapperFeature.DEFAULT_VIEW_INCLUSION;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.InstanceOfAssertFactories.BOOLEAN;
import static org.mockito.Mockito.mock;
import static org.springframework.http.MediaType.APPLICATION_JSON;
import static org.springframework.http.MediaType.APPLICATION_XML;
@ -240,8 +239,6 @@ class WebMvcConfigurationSupportExtensionTests {
DeferredResultProcessingInterceptor[] deferredResultInterceptors =
(DeferredResultProcessingInterceptor[]) fieldAccessor.getPropertyValue("deferredResultInterceptors");
assertThat(deferredResultInterceptors).hasSize(1);
assertThat(fieldAccessor.getPropertyValue("ignoreDefaultModelOnRedirect")).asInstanceOf(BOOLEAN).isTrue();
}
@Test

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2024 the original author or authors.
* Copyright 2002-2025 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.
@ -99,7 +99,6 @@ import static org.assertj.core.api.Assertions.assertThat;
import static org.springframework.web.servlet.DispatcherServlet.FLASH_MAP_MANAGER_BEAN_NAME;
import static org.springframework.web.servlet.DispatcherServlet.LOCALE_RESOLVER_BEAN_NAME;
import static org.springframework.web.servlet.DispatcherServlet.REQUEST_TO_VIEW_NAME_TRANSLATOR_BEAN_NAME;
import static org.springframework.web.servlet.DispatcherServlet.THEME_RESOLVER_BEAN_NAME;
/**
* Integration tests for {@link WebMvcConfigurationSupport} (imported via
@ -332,17 +331,6 @@ class WebMvcConfigurationSupportTests {
assertThat(localeResolver).isInstanceOf(AcceptHeaderLocaleResolver.class);
}
@Test
@SuppressWarnings("deprecation")
public void defaultThemeResolverConfiguration() {
ApplicationContext context = initContext(WebConfig.class);
org.springframework.web.servlet.ThemeResolver themeResolver =
context.getBean(THEME_RESOLVER_BEAN_NAME, org.springframework.web.servlet.ThemeResolver.class);
assertThat(themeResolver).isNotNull();
assertThat(themeResolver).isInstanceOf(org.springframework.web.servlet.theme.FixedThemeResolver.class);
}
@Test
void defaultFlashMapManagerConfiguration() {
ApplicationContext context = initContext(WebConfig.class);

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2024 the original author or authors.
* Copyright 2002-2025 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,9 +26,7 @@ import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.servlet.DispatcherServlet;
import org.springframework.web.servlet.LocaleResolver;
import org.springframework.web.servlet.SimpleWebApplicationContext;
import org.springframework.web.servlet.ThemeResolver;
import org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver;
import org.springframework.web.servlet.theme.FixedThemeResolver;
import org.springframework.web.testfixture.servlet.MockHttpServletRequest;
import org.springframework.web.testfixture.servlet.MockHttpServletResponse;
import org.springframework.web.testfixture.servlet.MockPageContext;
@ -57,9 +55,6 @@ public abstract class AbstractTagTests {
request.setAttribute(DispatcherServlet.WEB_APPLICATION_CONTEXT_ATTRIBUTE, wac);
LocaleResolver lr = new AcceptHeaderLocaleResolver();
request.setAttribute(DispatcherServlet.LOCALE_RESOLVER_ATTRIBUTE, lr);
ThemeResolver tr = new FixedThemeResolver();
request.setAttribute(DispatcherServlet.THEME_RESOLVER_ATTRIBUTE, tr);
request.setAttribute(DispatcherServlet.THEME_SOURCE_ATTRIBUTE, wac);
}
else {
sc.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, wac);

View File

@ -1,74 +0,0 @@
/*
* Copyright 2002-2024 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
*
* https://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.tags;
import java.util.List;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.jsp.JspException;
import jakarta.servlet.jsp.PageContext;
import jakarta.servlet.jsp.tagext.Tag;
import org.junit.jupiter.api.Test;
import org.springframework.context.MessageSourceResolvable;
import org.springframework.context.support.DefaultMessageSourceResolvable;
import org.springframework.web.servlet.support.RequestContext;
import static org.assertj.core.api.Assertions.assertThat;
/**
* @author Juergen Hoeller
* @author Alef Arendsen
*/
@SuppressWarnings("deprecation")
class ThemeTagTests extends AbstractTagTests {
@Test
void themeTag() throws JspException {
PageContext pc = createPageContext();
final StringBuilder message = new StringBuilder();
ThemeTag tag = new ThemeTag() {
@Override
protected void writeMessage(String msg) {
message.append(msg);
}
};
tag.setPageContext(pc);
tag.setCode("themetest");
assertThat(tag.doStartTag()).as("Correct doStartTag return value").isEqualTo(Tag.EVAL_BODY_INCLUDE);
assertThat(tag.doEndTag()).as("Correct doEndTag return value").isEqualTo(Tag.EVAL_PAGE);
assertThat(message.toString()).isEqualTo("theme test message");
}
@Test
@SuppressWarnings("rawtypes")
void requestContext() {
PageContext pc = createPageContext();
RequestContext rc = new RequestContext((HttpServletRequest) pc.getRequest());
assertThat(rc.getThemeMessage("themetest")).isEqualTo("theme test message");
assertThat(rc.getThemeMessage("themetest", (String[]) null)).isEqualTo("theme test message");
assertThat(rc.getThemeMessage("themetest", "default")).isEqualTo("theme test message");
assertThat(rc.getThemeMessage("themetest", (Object[]) null, "default")).isEqualTo("theme test message");
assertThat(rc.getThemeMessage("themetestArgs", new String[]{"arg1"})).isEqualTo("theme test message arg1");
assertThat(rc.getThemeMessage("themetestArgs", List.of("arg1"))).isEqualTo("theme test message arg1");
assertThat(rc.getThemeMessage("themetesta", "default")).isEqualTo("default");
assertThat(rc.getThemeMessage("themetesta", (List) null, "default")).isEqualTo("default");
MessageSourceResolvable resolvable = new DefaultMessageSourceResolvable(new String[] {"themetest"});
assertThat(rc.getThemeMessage(resolvable)).isEqualTo("theme test message");
}
}

View File

@ -1,86 +0,0 @@
/*
* Copyright 2002-2024 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
*
* https://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.theme;
import org.junit.jupiter.api.Test;
import org.springframework.web.servlet.ThemeResolver;
import org.springframework.web.testfixture.servlet.MockHttpServletRequest;
import org.springframework.web.testfixture.servlet.MockHttpServletResponse;
import org.springframework.web.testfixture.servlet.MockServletContext;
import static org.assertj.core.api.Assertions.assertThat;
/**
* @author Jean-Pierre Pawlak
* @author Juergen Hoeller
* @since 19.06.2003
*/
@SuppressWarnings("deprecation")
public class ThemeResolverTests {
private static final String TEST_THEME_NAME = "test.theme";
private static final String DEFAULT_TEST_THEME_NAME = "default.theme";
private void internalTest(ThemeResolver themeResolver, boolean shouldSet, String defaultName) {
// create mocks
MockServletContext context = new MockServletContext();
MockHttpServletRequest request = new MockHttpServletRequest(context);
MockHttpServletResponse response = new MockHttpServletResponse();
// check original theme
String themeName = themeResolver.resolveThemeName(request);
assertThat(defaultName).isEqualTo(themeName);
// set new theme name
try {
themeResolver.setThemeName(request, response, TEST_THEME_NAME);
assertThat(shouldSet).as("able to set theme name").isTrue();
// check new theme namelocale
themeName = themeResolver.resolveThemeName(request);
assertThat(themeName).isEqualTo(TEST_THEME_NAME);
themeResolver.setThemeName(request, response, null);
themeName = themeResolver.resolveThemeName(request);
assertThat(defaultName).isEqualTo(themeName);
}
catch (UnsupportedOperationException ex) {
assertThat(shouldSet).as("able to set theme name").isFalse();
}
}
@Test
void fixedThemeResolver() {
internalTest(new FixedThemeResolver(), false, AbstractThemeResolver.ORIGINAL_DEFAULT_THEME_NAME);
}
@Test
@SuppressWarnings("removal")
void cookieThemeResolver() {
internalTest(new CookieThemeResolver(), true, AbstractThemeResolver.ORIGINAL_DEFAULT_THEME_NAME);
}
@Test
void sessionThemeResolver() {
internalTest(new SessionThemeResolver(), true,AbstractThemeResolver.ORIGINAL_DEFAULT_THEME_NAME);
}
@Test
void sessionThemeResolverWithDefault() {
SessionThemeResolver tr = new SessionThemeResolver();
tr.setDefaultThemeName(DEFAULT_TEST_THEME_NAME);
internalTest(tr, true, DEFAULT_TEST_THEME_NAME);
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2024 the original author or authors.
* Copyright 2002-2025 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.
@ -45,7 +45,6 @@ import org.springframework.web.servlet.View;
import org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver;
import org.springframework.web.servlet.i18n.FixedLocaleResolver;
import org.springframework.web.servlet.support.RequestContext;
import org.springframework.web.servlet.theme.FixedThemeResolver;
import org.springframework.web.testfixture.servlet.MockHttpServletRequest;
import org.springframework.web.testfixture.servlet.MockHttpServletResponse;
import org.springframework.web.testfixture.servlet.MockRequestDispatcher;
@ -177,7 +176,6 @@ class ViewResolverTests {
this.request.setAttribute(DispatcherServlet.WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.wac);
this.request.setAttribute(DispatcherServlet.LOCALE_RESOLVER_ATTRIBUTE, new AcceptHeaderLocaleResolver());
this.request.setAttribute(DispatcherServlet.THEME_RESOLVER_ATTRIBUTE, new FixedThemeResolver());
Map<String, Object> model = new HashMap<>();
TestBean tb = new TestBean();
model.put("tb", tb);
@ -422,7 +420,6 @@ class ViewResolverTests {
this.request.setAttribute(DispatcherServlet.WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.wac);
this.request.setAttribute(DispatcherServlet.LOCALE_RESOLVER_ATTRIBUTE, new AcceptHeaderLocaleResolver());
this.request.setAttribute(DispatcherServlet.THEME_RESOLVER_ATTRIBUTE, new FixedThemeResolver());
view1.render(model, this.request, this.response);
assertThat(tb.equals(this.request.getAttribute("tb"))).as("Correct tb attribute").isTrue();
assertThat(this.request.getAttribute("test1")).as("Correct test1 attribute").isEqualTo("testvalue1");
@ -431,7 +428,6 @@ class ViewResolverTests {
this.request.clearAttributes();
this.request.setAttribute(DispatcherServlet.WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.wac);
this.request.setAttribute(DispatcherServlet.LOCALE_RESOLVER_ATTRIBUTE, new AcceptHeaderLocaleResolver());
this.request.setAttribute(DispatcherServlet.THEME_RESOLVER_ATTRIBUTE, new FixedThemeResolver());
view2.render(model, this.request, this.response);
assertThat(tb.equals(this.request.getAttribute("tb"))).as("Correct tb attribute").isTrue();
assertThat(this.request.getAttribute("test1")).as("Correct test1 attribute").isEqualTo("testvalue1");

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2024 the original author or authors.
* Copyright 2002-2025 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.
@ -43,7 +43,6 @@ import org.springframework.web.servlet.DispatcherServlet;
import org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver;
import org.springframework.web.servlet.support.BindStatus;
import org.springframework.web.servlet.support.RequestContext;
import org.springframework.web.servlet.theme.FixedThemeResolver;
import org.springframework.web.servlet.view.AbstractTemplateView;
import org.springframework.web.servlet.view.DummyMacroRequestContext;
import org.springframework.web.testfixture.servlet.MockHttpServletRequest;
@ -90,7 +89,6 @@ public class FreeMarkerMacroTests {
request.setAttribute(DispatcherServlet.WEB_APPLICATION_CONTEXT_ATTRIBUTE, wac);
request.setAttribute(DispatcherServlet.LOCALE_RESOLVER_ATTRIBUTE, new AcceptHeaderLocaleResolver());
request.setAttribute(DispatcherServlet.THEME_RESOLVER_ATTRIBUTE, new FixedThemeResolver());
}

View File

@ -7,8 +7,6 @@
<import resource="resources/messageSource.xml"/>
<import resource="/resources/../resources/themeSource.xml"/>
<bean id="lifecyclePostProcessor" class="org.springframework.beans.testfixture.beans.LifecycleBean$PostProcessor"/>
<!--

View File

@ -1,12 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" "https://www.springframework.org/dtd/spring-beans-2.0.dtd">
<beans>
<bean id="themeSource" class="org.springframework.ui.context.support.ResourceBundleThemeSource">
<property name="basenamePrefix">
<value>${theme-base}</value>
</property>
</bean>
</beans>

View File

@ -7,10 +7,6 @@
<property name="basename"><value>org/springframework/web/context/WEB-INF/test-messages</value></property>
</bean>
<bean id="themeSource" class="org.springframework.ui.context.support.ResourceBundleThemeSource">
<property name="basenamePrefix"><value>org/springframework/web/context/WEB-INF/test-</value></property>
</bean>
<bean id="aca" class="org.springframework.context.testfixture.beans.ACATester"/>
<bean id="aca-prototype" class="org.springframework.context.testfixture.beans.ACATester" scope="prototype"/>

View File

@ -10,9 +10,6 @@
<mvc:interceptors>
<bean class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor" p:paramName="lang" />
<bean class="org.springframework.web.servlet.theme.ThemeChangeInterceptor">
<property name="paramName" value="style" />
</bean>
</mvc:interceptors>
</beans>

View File

@ -5,8 +5,7 @@
xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd">
<mvc:annotation-driven validator="validator"
ignore-default-model-on-redirect="true" enable-matrix-variables="true" />
<mvc:annotation-driven validator="validator" enable-matrix-variables="true" />
<bean id="validator" class="org.springframework.web.servlet.config.MvcNamespaceTests$TestValidator" />

View File

@ -9,12 +9,6 @@
<mvc:interceptors>
<bean class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor"/>
<mvc:interceptor>
<mvc:mapping path="/**" />
<mvc:exclude-mapping path="/admin/**" />
<mvc:exclude-mapping path="/images/**" />
<bean class="org.springframework.web.servlet.theme.ThemeChangeInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>
<mvc:interceptors path-matcher="pathMatcher">

View File

@ -19,7 +19,6 @@
<mvc:interceptors>
<bean class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor"/>
<bean class="org.springframework.web.servlet.theme.ThemeChangeInterceptor"/>
</mvc:interceptors>
</beans>