mirror of
https://github.com/spring-projects/spring-framework.git
synced 2026-10-02 20:49:02 +00:00
Merge branch '7.0.x'
# Conflicts: # spring-context/src/main/java/org/springframework/validation/DataBinder.java
This commit is contained in:
@@ -49,7 +49,7 @@ import java.beans.PropertyDescriptor;
|
||||
public interface BeanWrapper extends ConfigurablePropertyAccessor {
|
||||
|
||||
/**
|
||||
* Specify a limit for array and collection auto-growing.
|
||||
* Specify a limit for array and collection/set/list auto-growing.
|
||||
* <p>Default is unlimited on a plain BeanWrapper.
|
||||
* @since 4.1
|
||||
*/
|
||||
|
||||
@@ -295,8 +295,13 @@ class TypeConverterDelegate {
|
||||
ClassLoader cl = this.targetObject.getClass().getClassLoader();
|
||||
try {
|
||||
Class<?> enumValueType = ClassUtils.forName(enumType, cl);
|
||||
Field enumField = enumValueType.getField(fieldName);
|
||||
convertedValue = enumField.get(null);
|
||||
if (enumValueType.isEnum()) {
|
||||
Field enumField = enumValueType.getField(fieldName);
|
||||
convertedValue = enumField.get(null);
|
||||
}
|
||||
else if (logger.isTraceEnabled()) {
|
||||
logger.trace("Specified enum class [" + enumType + "] is not a Java enum");
|
||||
}
|
||||
}
|
||||
catch (ClassNotFoundException ex) {
|
||||
if (logger.isTraceEnabled()) {
|
||||
@@ -313,8 +318,7 @@ class TypeConverterDelegate {
|
||||
|
||||
if (convertedValue == currentConvertedValue) {
|
||||
// Try field lookup as fallback: for Java enum or custom enum
|
||||
// with values defined as static fields. Resulting value still needs
|
||||
// to be checked, hence we don't return it right away.
|
||||
// with values defined as static fields.
|
||||
try {
|
||||
Field enumField = requiredType.getField(trimmedValue);
|
||||
ReflectionUtils.makeAccessible(enumField);
|
||||
|
||||
+41
-16
@@ -17,15 +17,19 @@
|
||||
package org.springframework.context.support;
|
||||
|
||||
import java.text.MessageFormat;
|
||||
import java.util.Arrays;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Base class for message source implementations, providing support infrastructure
|
||||
@@ -41,6 +45,9 @@ import org.springframework.util.ObjectUtils;
|
||||
*/
|
||||
public abstract class MessageSourceSupport {
|
||||
|
||||
static final Set<Locale> JVM_LOCALES = Arrays.stream(Locale.getAvailableLocales()).
|
||||
filter(l -> StringUtils.hasLength(l.getLanguage())).collect(Collectors.toSet());
|
||||
|
||||
private static final MessageFormat INVALID_MESSAGE_FORMAT = new MessageFormat("");
|
||||
|
||||
/** Logger available to subclasses. */
|
||||
@@ -116,22 +123,17 @@ public abstract class MessageSourceSupport {
|
||||
if (!isAlwaysUseMessageFormat() && ObjectUtils.isEmpty(args)) {
|
||||
return msg;
|
||||
}
|
||||
Map<Locale, MessageFormat> messageFormatsPerLocale = this.messageFormatsPerMessage
|
||||
.computeIfAbsent(msg, key -> new ConcurrentHashMap<>());
|
||||
MessageFormat messageFormat = messageFormatsPerLocale.computeIfAbsent(locale, key -> {
|
||||
try {
|
||||
return createMessageFormat(msg, locale);
|
||||
}
|
||||
catch (IllegalArgumentException ex) {
|
||||
// Invalid message format - probably not intended for formatting,
|
||||
// rather using a message structure with no arguments involved...
|
||||
if (isAlwaysUseMessageFormat()) {
|
||||
throw ex;
|
||||
}
|
||||
// Silently proceed with raw message if format not enforced...
|
||||
return INVALID_MESSAGE_FORMAT;
|
||||
}
|
||||
});
|
||||
|
||||
MessageFormat messageFormat;
|
||||
if (locale != null && JVM_LOCALES.contains(locale)) {
|
||||
Map<Locale, MessageFormat> messageFormatsPerLocale = this.messageFormatsPerMessage
|
||||
.computeIfAbsent(msg, key -> new ConcurrentHashMap<>());
|
||||
messageFormat = messageFormatsPerLocale.computeIfAbsent(locale, key -> resolveMessageFormat(msg, key));
|
||||
}
|
||||
else {
|
||||
messageFormat = resolveMessageFormat(msg, locale);
|
||||
}
|
||||
|
||||
if (messageFormat == INVALID_MESSAGE_FORMAT) {
|
||||
return msg;
|
||||
}
|
||||
@@ -140,6 +142,29 @@ public abstract class MessageSourceSupport {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve a {@code MessageFormat} for the given message and Locale.
|
||||
* @param msg the message to create a {@code MessageFormat} for
|
||||
* @param locale the Locale to create a {@code MessageFormat} for
|
||||
* @return the {@code MessageFormat} instance, or otherwise
|
||||
* {@link #INVALID_MESSAGE_FORMAT} if not resolvable
|
||||
* @see #createMessageFormat
|
||||
*/
|
||||
private MessageFormat resolveMessageFormat(String msg, @Nullable Locale locale) {
|
||||
try {
|
||||
return createMessageFormat(msg, locale);
|
||||
}
|
||||
catch (IllegalArgumentException ex) {
|
||||
// Invalid message format - probably not intended for formatting,
|
||||
// rather using a message structure with no arguments involved...
|
||||
if (isAlwaysUseMessageFormat()) {
|
||||
throw ex;
|
||||
}
|
||||
// Silently proceed with raw message if format not enforced...
|
||||
return INVALID_MESSAGE_FORMAT;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a {@code MessageFormat} for the given message and Locale.
|
||||
* @param msg the message to create a {@code MessageFormat} for
|
||||
|
||||
+67
-45
@@ -40,6 +40,7 @@ import org.springframework.core.io.Resource;
|
||||
import org.springframework.core.io.ResourceLoader;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.ConcurrentLruCache;
|
||||
import org.springframework.util.DefaultPropertiesPersister;
|
||||
import org.springframework.util.PropertiesPersister;
|
||||
import org.springframework.util.StringUtils;
|
||||
@@ -114,15 +115,19 @@ public class ReloadableResourceBundleMessageSource extends AbstractResourceBased
|
||||
|
||||
private ResourceLoader resourceLoader = new DefaultResourceLoader();
|
||||
|
||||
// Cache to hold filename lists per Locale
|
||||
// Cache to hold filename lists per Locale.
|
||||
private final ConcurrentMap<String, Map<Locale, List<String>>> cachedFilenames = new ConcurrentHashMap<>();
|
||||
|
||||
// Cache to hold already loaded properties per filename
|
||||
// Cache to hold already loaded properties per filename.
|
||||
private final ConcurrentMap<String, PropertiesHolder> cachedProperties = new ConcurrentHashMap<>();
|
||||
|
||||
// Cache to hold already loaded properties per filename
|
||||
// Cache to hold already merged properties per Locale.
|
||||
private final ConcurrentMap<Locale, PropertiesHolder> cachedMergedProperties = new ConcurrentHashMap<>();
|
||||
|
||||
// Cache to hold merged properties per non-JVM Locale.
|
||||
private final ConcurrentLruCache<Locale, PropertiesHolder> customLocaleProperties =
|
||||
new ConcurrentLruCache<>(64, locale -> mergeProperties(collectPropertiesToMerge(locale)));
|
||||
|
||||
|
||||
/**
|
||||
* Set the list of supported file extensions.
|
||||
@@ -201,20 +206,16 @@ public class ReloadableResourceBundleMessageSource extends AbstractResourceBased
|
||||
protected @Nullable String resolveCodeWithoutArguments(String code, Locale locale) {
|
||||
if (getCacheMillis() < 0) {
|
||||
PropertiesHolder propHolder = getMergedProperties(locale);
|
||||
String result = propHolder.getProperty(code);
|
||||
if (result != null) {
|
||||
return result;
|
||||
}
|
||||
return propHolder.getProperty(code);
|
||||
}
|
||||
else {
|
||||
for (String basename : getBasenameSet()) {
|
||||
List<String> filenames = calculateAllFilenames(basename, locale);
|
||||
for (String filename : filenames) {
|
||||
PropertiesHolder propHolder = getProperties(filename);
|
||||
String result = propHolder.getProperty(code);
|
||||
if (result != null) {
|
||||
return result;
|
||||
}
|
||||
|
||||
for (String basename : getBasenameSet()) {
|
||||
List<String> filenames = calculateAllFilenames(basename, locale);
|
||||
for (String filename : filenames) {
|
||||
PropertiesHolder propHolder = getProperties(filename, locale);
|
||||
String result = propHolder.getProperty(code);
|
||||
if (result != null) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -229,20 +230,16 @@ public class ReloadableResourceBundleMessageSource extends AbstractResourceBased
|
||||
protected @Nullable MessageFormat resolveCode(String code, Locale locale) {
|
||||
if (getCacheMillis() < 0) {
|
||||
PropertiesHolder propHolder = getMergedProperties(locale);
|
||||
MessageFormat result = propHolder.getMessageFormat(code, locale);
|
||||
if (result != null) {
|
||||
return result;
|
||||
}
|
||||
return propHolder.getMessageFormat(code, locale);
|
||||
}
|
||||
else {
|
||||
for (String basename : getBasenameSet()) {
|
||||
List<String> filenames = calculateAllFilenames(basename, locale);
|
||||
for (String filename : filenames) {
|
||||
PropertiesHolder propHolder = getProperties(filename);
|
||||
MessageFormat result = propHolder.getMessageFormat(code, locale);
|
||||
if (result != null) {
|
||||
return result;
|
||||
}
|
||||
|
||||
for (String basename : getBasenameSet()) {
|
||||
List<String> filenames = calculateAllFilenames(basename, locale);
|
||||
for (String filename : filenames) {
|
||||
PropertiesHolder propHolder = getProperties(filename, locale);
|
||||
MessageFormat result = propHolder.getMessageFormat(code, locale);
|
||||
if (result != null) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -265,12 +262,18 @@ public class ReloadableResourceBundleMessageSource extends AbstractResourceBased
|
||||
if (mergedHolder != null) {
|
||||
return mergedHolder;
|
||||
}
|
||||
mergedHolder = mergeProperties(collectPropertiesToMerge(locale));
|
||||
PropertiesHolder existing = this.cachedMergedProperties.putIfAbsent(locale, mergedHolder);
|
||||
if (existing != null) {
|
||||
mergedHolder = existing;
|
||||
|
||||
if (JVM_LOCALES.contains(locale)) {
|
||||
mergedHolder = mergeProperties(collectPropertiesToMerge(locale));
|
||||
PropertiesHolder existing = this.cachedMergedProperties.putIfAbsent(locale, mergedHolder);
|
||||
if (existing != null) {
|
||||
mergedHolder = existing;
|
||||
}
|
||||
return mergedHolder;
|
||||
}
|
||||
else {
|
||||
return this.customLocaleProperties.get(locale);
|
||||
}
|
||||
return mergedHolder;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -289,7 +292,7 @@ public class ReloadableResourceBundleMessageSource extends AbstractResourceBased
|
||||
List<String> filenames = calculateAllFilenames(basenames[i], locale);
|
||||
for (int j = filenames.size() - 1; j >= 0; j--) {
|
||||
String filename = filenames.get(j);
|
||||
PropertiesHolder propHolder = getProperties(filename);
|
||||
PropertiesHolder propHolder = getProperties(filename, locale);
|
||||
if (propHolder.getProperties() != null) {
|
||||
holders.add(propHolder);
|
||||
}
|
||||
@@ -338,11 +341,11 @@ public class ReloadableResourceBundleMessageSource extends AbstractResourceBased
|
||||
}
|
||||
}
|
||||
|
||||
// Filenames for given Locale
|
||||
// Filenames for given Locale.
|
||||
List<String> filenames = new ArrayList<>(7);
|
||||
filenames.addAll(calculateFilenamesForLocale(basename, locale));
|
||||
|
||||
// Filenames for default Locale, if any
|
||||
// Filenames for default Locale, if any.
|
||||
Locale defaultLocale = getDefaultLocale();
|
||||
if (defaultLocale != null && !defaultLocale.equals(locale)) {
|
||||
List<String> fallbackFilenames = calculateFilenamesForLocale(basename, defaultLocale);
|
||||
@@ -354,24 +357,27 @@ public class ReloadableResourceBundleMessageSource extends AbstractResourceBased
|
||||
}
|
||||
}
|
||||
|
||||
// Filename for default bundle file
|
||||
// Filename for default bundle file.
|
||||
filenames.add(basename);
|
||||
|
||||
if (localeMap == null) {
|
||||
localeMap = new ConcurrentHashMap<>();
|
||||
Map<Locale, List<String>> existing = this.cachedFilenames.putIfAbsent(basename, localeMap);
|
||||
if (existing != null) {
|
||||
localeMap = existing;
|
||||
if (JVM_LOCALES.contains(locale)) {
|
||||
if (localeMap == null) {
|
||||
localeMap = new ConcurrentHashMap<>();
|
||||
Map<Locale, List<String>> existing = this.cachedFilenames.putIfAbsent(basename, localeMap);
|
||||
if (existing != null) {
|
||||
localeMap = existing;
|
||||
}
|
||||
}
|
||||
localeMap.put(locale, filenames);
|
||||
}
|
||||
localeMap.put(locale, filenames);
|
||||
|
||||
return filenames;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate the filenames for the given bundle basename and Locale,
|
||||
* appending language code, country code, and variant code.
|
||||
* <p>For example, basename "messages", Locale "de_AT_oo" → "messages_de_AT_OO",
|
||||
* <p>For example, basename "messages", Locale "de_AT_OO" → "messages_de_AT_OO",
|
||||
* "messages_de_AT", "messages_de".
|
||||
* <p>Follows the rules defined by {@link java.util.Locale#toString()}.
|
||||
* @param basename the basename of the bundle
|
||||
@@ -406,6 +412,22 @@ public class ReloadableResourceBundleMessageSource extends AbstractResourceBased
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get a PropertiesHolder for the given filename, either from the
|
||||
* cache or freshly loaded.
|
||||
* @param filename the bundle filename (basename + Locale)
|
||||
* @param locale the requested locale (for cache filtering)
|
||||
* @return the current PropertiesHolder for the bundle
|
||||
* @see #getProperties(String)
|
||||
*/
|
||||
private PropertiesHolder getProperties(String filename, Locale locale) {
|
||||
PropertiesHolder propHolder = getProperties(filename);
|
||||
if (propHolder.getProperties() == null && !JVM_LOCALES.contains(locale)) {
|
||||
this.cachedProperties.remove(filename);
|
||||
}
|
||||
return propHolder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a PropertiesHolder for the given filename, either from the
|
||||
* cache or freshly loaded.
|
||||
|
||||
+27
-23
@@ -188,36 +188,35 @@ public class ResourceBundleMessageSource extends AbstractResourceBasedMessageSou
|
||||
* found for the given basename and Locale
|
||||
*/
|
||||
protected @Nullable ResourceBundle getResourceBundle(String basename, Locale locale) {
|
||||
if (getCacheMillis() >= 0) {
|
||||
if (getCacheMillis() >= 0 || !JVM_LOCALES.contains(locale)) {
|
||||
// Fresh ResourceBundle.getBundle call in order to let ResourceBundle
|
||||
// do its native caching, at the expense of more extensive lookup steps.
|
||||
return doGetBundle(basename, locale);
|
||||
}
|
||||
else {
|
||||
// Cache forever: prefer locale cache over repeated getBundle calls.
|
||||
Map<Locale, ResourceBundle> localeMap = this.cachedResourceBundles.get(basename);
|
||||
if (localeMap != null) {
|
||||
ResourceBundle bundle = localeMap.get(locale);
|
||||
if (bundle != null) {
|
||||
return bundle;
|
||||
}
|
||||
}
|
||||
try {
|
||||
ResourceBundle bundle = doGetBundle(basename, locale);
|
||||
if (localeMap == null) {
|
||||
localeMap = this.cachedResourceBundles.computeIfAbsent(basename, bn -> new ConcurrentHashMap<>());
|
||||
}
|
||||
localeMap.put(locale, bundle);
|
||||
|
||||
// Cache forever: prefer local cache over repeated getBundle calls.
|
||||
Map<Locale, ResourceBundle> localeMap = this.cachedResourceBundles.get(basename);
|
||||
if (localeMap != null) {
|
||||
ResourceBundle bundle = localeMap.get(locale);
|
||||
if (bundle != null) {
|
||||
return bundle;
|
||||
}
|
||||
catch (MissingResourceException ex) {
|
||||
if (logger.isWarnEnabled()) {
|
||||
logger.warn("ResourceBundle [" + basename + "] not found for MessageSource: " + ex.getMessage());
|
||||
}
|
||||
// Assume bundle not found
|
||||
// -> do NOT throw the exception to allow for checking parent message source.
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
ResourceBundle bundle = doGetBundle(basename, locale);
|
||||
if (localeMap == null) {
|
||||
localeMap = this.cachedResourceBundles.computeIfAbsent(basename, bn -> new ConcurrentHashMap<>());
|
||||
}
|
||||
localeMap.put(locale, bundle);
|
||||
return bundle;
|
||||
}
|
||||
catch (MissingResourceException ex) {
|
||||
if (logger.isWarnEnabled()) {
|
||||
logger.warn("ResourceBundle [" + basename + "] not found for MessageSource: " + ex.getMessage());
|
||||
}
|
||||
// Assume bundle not found
|
||||
// -> do NOT throw the exception to allow for checking parent message source.
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -311,6 +310,11 @@ public class ResourceBundleMessageSource extends AbstractResourceBasedMessageSou
|
||||
protected @Nullable MessageFormat getMessageFormat(ResourceBundle bundle, String code, Locale locale)
|
||||
throws MissingResourceException {
|
||||
|
||||
if (!JVM_LOCALES.contains(locale)) {
|
||||
String msg = getStringOrNull(bundle, code);
|
||||
return (msg != null ? createMessageFormat(msg, locale) : null);
|
||||
}
|
||||
|
||||
Map<String, Map<Locale, MessageFormat>> codeMap = this.cachedBundleMessageFormats.get(bundle);
|
||||
Map<Locale, MessageFormat> localeMap = null;
|
||||
if (codeMap != null) {
|
||||
|
||||
@@ -270,12 +270,12 @@ public class DataBinder implements PropertyEditorRegistry, TypeConverter {
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify the limit for array and collection auto-growing.
|
||||
* Specify the limit for array and collection/set/list auto-growing.
|
||||
* <p>Default is 256, preventing OutOfMemoryErrors in case of large indexes.
|
||||
* Raise this limit if your auto-growing needs are unusually high.
|
||||
* <p>Used for setter injection - and as of 7.1 also for field injection -
|
||||
* via {@link #bind(PropertyValues)}; not applicable to constructor binding
|
||||
* via {@link #construct}.
|
||||
* via {@link #bind(PropertyValues)}; not applicable to map properties and
|
||||
* not to constructor binding via {@link #construct} either.
|
||||
* @see #initBeanPropertyAccess()
|
||||
* @see org.springframework.beans.BeanWrapper#setAutoGrowCollectionLimit
|
||||
*/
|
||||
@@ -326,6 +326,8 @@ public class DataBinder implements PropertyEditorRegistry, TypeConverter {
|
||||
/**
|
||||
* Initialize direct field access for this DataBinder,
|
||||
* as alternative to the default bean property access.
|
||||
* <p><b>NOTE: This is an advanced option for trusted scenarios.</b>
|
||||
* Do not use direct field access for data binding from untrusted sources.
|
||||
* @see #initBeanPropertyAccess()
|
||||
* @see #createDirectFieldBindingResult()
|
||||
*/
|
||||
|
||||
+3
-3
@@ -100,20 +100,20 @@ public class LocalizedResourceHelper {
|
||||
String variant = locale.getVariant();
|
||||
|
||||
// Check for file with language, country and variant localization.
|
||||
if (variant.length() > 0) {
|
||||
if (!variant.isEmpty()) {
|
||||
String location =
|
||||
name + this.separator + lang + this.separator + country + this.separator + variant + extension;
|
||||
resource = this.resourceLoader.getResource(location);
|
||||
}
|
||||
|
||||
// Check for file with language and country localization.
|
||||
if ((resource == null || !resource.exists()) && country.length() > 0) {
|
||||
if ((resource == null || !resource.exists()) && !country.isEmpty()) {
|
||||
String location = name + this.separator + lang + this.separator + country + extension;
|
||||
resource = this.resourceLoader.getResource(location);
|
||||
}
|
||||
|
||||
// Check for document with language localization.
|
||||
if ((resource == null || !resource.exists()) && lang.length() > 0) {
|
||||
if ((resource == null || !resource.exists()) && !lang.isEmpty()) {
|
||||
String location = name + this.separator + lang + extension;
|
||||
resource = this.resourceLoader.getResource(location);
|
||||
}
|
||||
|
||||
+33
-1
@@ -18,6 +18,7 @@ package org.springframework.core.serializer;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.ObjectInputFilter;
|
||||
import java.io.ObjectInputStream;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
@@ -38,6 +39,8 @@ public class DefaultDeserializer implements Deserializer<Object> {
|
||||
|
||||
private final @Nullable ClassLoader classLoader;
|
||||
|
||||
private final @Nullable ObjectInputFilter objectInputFilter;
|
||||
|
||||
|
||||
/**
|
||||
* Create a {@code DefaultDeserializer} with default {@link ObjectInputStream}
|
||||
@@ -45,6 +48,7 @@ public class DefaultDeserializer implements Deserializer<Object> {
|
||||
*/
|
||||
public DefaultDeserializer() {
|
||||
this.classLoader = null;
|
||||
this.objectInputFilter = null;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -56,6 +60,21 @@ public class DefaultDeserializer implements Deserializer<Object> {
|
||||
*/
|
||||
public DefaultDeserializer(@Nullable ClassLoader classLoader) {
|
||||
this.classLoader = classLoader;
|
||||
this.objectInputFilter = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a {@code DefaultDeserializer} for using an {@link ObjectInputStream}
|
||||
* with the given {@code ClassLoader}.
|
||||
* @param classLoader the ClassLoader to use
|
||||
* @param objectInputFilter a custom ObjectInputFilter to apply
|
||||
* @since 7.0.9
|
||||
* @see ConfigurableObjectInputStream#ConfigurableObjectInputStream(InputStream, ClassLoader)
|
||||
* @see ObjectInputStream#setObjectInputFilter
|
||||
*/
|
||||
public DefaultDeserializer(@Nullable ClassLoader classLoader, @Nullable ObjectInputFilter objectInputFilter) {
|
||||
this.classLoader = classLoader;
|
||||
this.objectInputFilter = objectInputFilter;
|
||||
}
|
||||
|
||||
|
||||
@@ -65,10 +84,20 @@ public class DefaultDeserializer implements Deserializer<Object> {
|
||||
* @since 6.2.19
|
||||
* @see ConfigurableObjectInputStream#ConfigurableObjectInputStream(InputStream, ClassLoader)
|
||||
*/
|
||||
public @Nullable ClassLoader getClassLoader() {
|
||||
public final @Nullable ClassLoader getClassLoader() {
|
||||
return this.classLoader;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the {@link ObjectInputFilter} to apply to the {@link ObjectInputStream},
|
||||
* if any.
|
||||
* @since 7.0.9
|
||||
* @see ObjectInputStream#setObjectInputFilter
|
||||
*/
|
||||
public final @Nullable ObjectInputFilter getObjectInputFilter() {
|
||||
return this.objectInputFilter;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Read from the supplied {@code InputStream} and deserialize the contents
|
||||
@@ -78,6 +107,9 @@ public class DefaultDeserializer implements Deserializer<Object> {
|
||||
@Override
|
||||
public Object deserialize(InputStream inputStream) throws IOException {
|
||||
ObjectInputStream objectInputStream = new ConfigurableObjectInputStream(inputStream, this.classLoader);
|
||||
if (this.objectInputFilter != null) {
|
||||
objectInputStream.setObjectInputFilter(this.objectInputFilter);
|
||||
}
|
||||
try {
|
||||
return objectInputStream.readObject();
|
||||
}
|
||||
|
||||
@@ -118,7 +118,7 @@ public abstract class FileSystemUtils {
|
||||
|
||||
/**
|
||||
* Recursively copy the contents of the {@code src} file/directory
|
||||
* to the {@code dest} file/directory.
|
||||
* to the {@code dest} file/directory, including symbolic links.
|
||||
* @param src the source directory
|
||||
* @param dest the destination directory
|
||||
* @throws IOException in the case of I/O errors
|
||||
|
||||
@@ -956,6 +956,7 @@ public abstract class StringUtils {
|
||||
String country = tokens[1];
|
||||
validateLocalePart(country);
|
||||
String variant = Arrays.stream(tokens).skip(2).collect(Collectors.joining(delimiter));
|
||||
validateLocalePart(variant);
|
||||
return new Locale(language, country, variant);
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -58,7 +58,7 @@ public class SqliteMaxValueIncrementer extends AbstractColumnMaxValueIncrementer
|
||||
|
||||
|
||||
@Override
|
||||
protected long getNextKey() {
|
||||
protected synchronized long getNextKey() {
|
||||
Connection con = DataSourceUtils.getConnection(getDataSource());
|
||||
Statement stmt = null;
|
||||
try {
|
||||
|
||||
+3
@@ -30,6 +30,9 @@ import org.springframework.util.Assert;
|
||||
* if the destination resolving process is expensive (for example, the destination has to be
|
||||
* resolved through an external system) and the resolution results are stable anyway.
|
||||
*
|
||||
* <p>Note: This cache is not designed for setups with varying dynamic destination names.
|
||||
* Prefer direct destination resolution in such scenarios.
|
||||
*
|
||||
* @author Agim Emruli
|
||||
* @author Juergen Hoeller
|
||||
* @since 4.1
|
||||
|
||||
+2
@@ -83,6 +83,8 @@ public class ConfigurableWebBindingInitializer implements WebBindingInitializer
|
||||
* Set whether to use direct field access instead of bean property access.
|
||||
* <p>Default is {@code false}, using bean property access.
|
||||
* Switch this to {@code true} in order to enforce direct field access.
|
||||
* <p><b>NOTE: This is an advanced option for trusted scenarios.</b>
|
||||
* Do not use direct field access for data binding from untrusted sources.
|
||||
* @see org.springframework.validation.DataBinder#initDirectFieldAccess()
|
||||
* @see org.springframework.validation.DataBinder#initBeanPropertyAccess()
|
||||
*/
|
||||
|
||||
+1
-1
@@ -124,7 +124,7 @@ class HtmlCharacterEntityDecoder {
|
||||
int value = (!isHexNumberedReference ?
|
||||
Integer.parseInt(getReferenceSubstring(2)) :
|
||||
Integer.parseInt(getReferenceSubstring(3), 16));
|
||||
if (value > Character.MAX_CODE_POINT) {
|
||||
if (value < 0 || value > Character.MAX_CODE_POINT) {
|
||||
return false;
|
||||
}
|
||||
this.decodedMessage.appendCodePoint(value);
|
||||
|
||||
+4
-3
@@ -51,6 +51,7 @@ public class ParameterizableViewController extends AbstractController {
|
||||
setSupportedMethods(HttpMethod.GET.name(), HttpMethod.HEAD.name());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set a view name for the ModelAndView to return, to be resolved by the
|
||||
* DispatcherServlet via a ViewResolver. Will override any pre-existing
|
||||
@@ -117,12 +118,11 @@ public class ParameterizableViewController extends AbstractController {
|
||||
return this.statusCode;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* The property can be used to indicate the request is considered fully
|
||||
* handled within the controller and that no view should be used for rendering.
|
||||
* Useful in combination with {@link #setStatusCode}.
|
||||
* <p>By default this is set to {@code false}.
|
||||
* <p>By default, this is set to {@code false}.
|
||||
* @since 4.1
|
||||
*/
|
||||
public void setStatusOnly(boolean statusOnly) {
|
||||
@@ -187,10 +187,11 @@ public class ParameterizableViewController extends AbstractController {
|
||||
sb.append("status=").append(this.statusCode);
|
||||
}
|
||||
if (this.view != null) {
|
||||
sb.append(sb.length() != 0 ? ", " : "");
|
||||
sb.append(!sb.isEmpty() ? ", " : "");
|
||||
String viewName = getViewName();
|
||||
sb.append("view=").append(viewName != null ? "\"" + viewName + "\"" : this.view);
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user