Commit d2188a36 authored by Emmanuel Bourg's avatar Emmanuel Bourg

New upstream version 4.3.21

parent cb53abe5
......@@ -41,7 +41,7 @@ configure(allprojects) { project ->
ext.fileuploadVersion = "1.3.3"
ext.freemarkerVersion = "2.3.23"
ext.groovyVersion = "2.4.15"
ext.gsonVersion = "2.8.2"
ext.gsonVersion = "2.8.5"
ext.guavaVersion = "20.0"
ext.hamcrestVersion = "1.3"
ext.hibernate3Version = "3.6.10.Final"
......@@ -50,9 +50,9 @@ configure(allprojects) { project ->
ext.hibval4Version = "4.3.2.Final"
ext.hibval5Version = "5.2.5.Final"
ext.hsqldbVersion = "2.3.4"
ext.httpasyncVersion = "4.1.3"
ext.httpclientVersion = "4.5.5"
ext.jackson2Version = "2.8.11.2"
ext.httpasyncVersion = "4.1.4"
ext.httpclientVersion = "4.5.6"
ext.jackson2Version = "2.8.11.3"
ext.jasperreportsVersion = "6.2.1" // our tests fail with JR-internal NPEs against 6.2.2 and higher
ext.javamailVersion = "1.5.6"
ext.jettyVersion = "9.3.14.v20161028" // as of 9.3.15, Jetty has hard Servlet 3.1 requirement
......@@ -62,7 +62,7 @@ configure(allprojects) { project ->
ext.jtaVersion = "1.2"
ext.junitVersion = "4.12"
ext.log4jVersion = "1.2.17"
ext.nettyVersion = "4.1.29.Final"
ext.nettyVersion = "4.1.31.Final"
ext.okhttpVersion = "2.7.5"
ext.okhttp3Version = "3.8.1"
ext.openjpaVersion = "2.4.2"
......@@ -71,11 +71,11 @@ configure(allprojects) { project ->
ext.romeVersion = "1.7.4"
ext.slf4jVersion = "1.7.25"
ext.snakeyamlVersion = "1.17"
ext.snifferVersion = "1.16"
ext.snifferVersion = "1.17"
ext.testngVersion = "6.9.10"
ext.tiles2Version = "2.2.2"
ext.tiles3Version = "3.0.7"
ext.tomcatVersion = "8.5.33"
ext.tiles3Version = "3.0.8"
ext.tomcatVersion = "8.5.35"
ext.tyrusVersion = "1.3.5" // constrained by WebLogic 12.1.3 support
ext.undertowVersion = "1.3.33.Final"
ext.xmlunitVersion = "1.6"
......@@ -289,10 +289,9 @@ project("spring-build-src") {
project("spring-core") {
description = "Spring Core"
// As of Spring 4.0.3, spring-core includes asm 5.x and repackages cglib 3.2, inlining
// both into the spring-core jar. cglib 3.2 itself depends on asm 5.x and is therefore
// further transformed by the JarJar task to depend on org.springframework.asm; this
// avoids including two different copies of asm unnecessarily.
// spring-core includes asm and repackages cglib, inlining both into the spring-core jar.
// cglib itself depends on asm and is therefore further transformed by the JarJar task to
// depend on org.springframework.asm; this avoids including two different copies of asm.
def cglibVersion = "3.2.6"
def objenesisVersion = "2.6"
......
version=4.3.20.RELEASE
version=4.3.21.RELEASE
/*
* Copyright 2002-2015 the original author or authors.
* Copyright 2002-2018 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,8 +43,10 @@ import org.springframework.util.ObjectUtils;
* Decorator for a standard {@link BeanInfo} object, e.g. as created by
* {@link Introspector#getBeanInfo(Class)}, designed to discover and register static
* and/or non-void returning setter methods. For example:
*
* <pre class="code">
* public class Bean {
*
* private Foo foo;
*
* public Foo getFoo() {
......@@ -56,6 +58,7 @@ import org.springframework.util.ObjectUtils;
* return this;
* }
* }</pre>
*
* The standard JavaBeans {@code Introspector} will discover the {@code getFoo} read
* method, but will bypass the {@code #setFoo(Foo)} write method, because its non-void
* returning signature does not comply with the JavaBeans specification.
......@@ -68,6 +71,7 @@ import org.springframework.util.ObjectUtils;
* indexed properties</a> are fully supported.
*
* @author Chris Beams
* @author Juergen Hoeller
* @since 3.1
* @see #ExtendedBeanInfo(BeanInfo)
* @see ExtendedBeanInfoFactory
......
/*
* Copyright 2002-2016 the original author or authors.
* Copyright 2002-2018 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.
......@@ -243,7 +243,9 @@ public interface ListableBeanFactory extends BeanFactory {
/**
* Find all names of beans whose {@code Class} has the supplied {@link Annotation}
* type, without creating any bean instances yet.
* type, without creating corresponding bean instances yet.
* <p>Note that this method considers objects created by FactoryBeans, which means
* that FactoryBeans will get initialized in order to determine their object type.
* @param annotationType the type of annotation to look for
* @return the names of all matching beans
* @since 4.0
......@@ -253,6 +255,8 @@ public interface ListableBeanFactory extends BeanFactory {
/**
* Find all beans whose {@code Class} has the supplied {@link Annotation} type,
* returning a Map of bean names with corresponding bean instances.
* <p>Note that this method considers objects created by FactoryBeans, which means
* that FactoryBeans will get initialized in order to determine their object type.
* @param annotationType the type of annotation to look for
* @return a Map with the matching beans, containing the bean names as
* keys and the corresponding bean instances as values
......@@ -267,7 +271,7 @@ public interface ListableBeanFactory extends BeanFactory {
* found on the given class itself.
* @param beanName the name of the bean to look for annotations on
* @param annotationType the annotation class to look for
* @return the annotation of the given type if found, or {@code null}
* @return the annotation of the given type if found, or {@code null} otherwise
* @throws NoSuchBeanDefinitionException if there is no bean with the given name
* @since 3.0
*/
......
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2018 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.
......@@ -44,24 +44,23 @@ public class AnnotationBeanWiringInfoResolver implements BeanWiringInfoResolver
}
/**
* Build the BeanWiringInfo for the given Configurable annotation.
* Build the {@link BeanWiringInfo} for the given {@link Configurable} annotation.
* @param beanInstance the bean instance
* @param annotation the Configurable annotation found on the bean class
* @return the resolved BeanWiringInfo
*/
protected BeanWiringInfo buildWiringInfo(Object beanInstance, Configurable annotation) {
if (!Autowire.NO.equals(annotation.autowire())) {
// Autowiring by name or by type
return new BeanWiringInfo(annotation.autowire().value(), annotation.dependencyCheck());
}
else if (!"".equals(annotation.value())) {
// Explicitly specified bean name for bean definition to take property values from
return new BeanWiringInfo(annotation.value(), false);
}
else {
if (!"".equals(annotation.value())) {
// explicitly specified bean name
return new BeanWiringInfo(annotation.value(), false);
}
else {
// default bean name
return new BeanWiringInfo(getDefaultBeanName(beanInstance), true);
}
// Default bean name for bean definition to take property values from
return new BeanWiringInfo(getDefaultBeanName(beanInstance), true);
}
}
......
......@@ -509,12 +509,21 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
// Generics potentially only match on the target class, not on the proxy...
RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
Class<?> targetType = mbd.getTargetType();
if (targetType != null && targetType != ClassUtils.getUserClass(beanInstance) &&
typeToMatch.isAssignableFrom(targetType)) {
if (targetType != null && targetType != ClassUtils.getUserClass(beanInstance)) {
// Check raw class match as well, making sure it's exposed on the proxy.
Class<?> classToMatch = typeToMatch.resolve();
return (classToMatch == null || classToMatch.isInstance(beanInstance));
if (classToMatch != null && !classToMatch.isInstance(beanInstance)) {
return false;
}
if (typeToMatch.isAssignableFrom(targetType)) {
return true;
}
}
ResolvableType resolvableType = mbd.targetType;
if (resolvableType == null) {
resolvableType = mbd.factoryMethodReturnType;
}
return (resolvableType != null && typeToMatch.isAssignableFrom(resolvableType));
}
}
return false;
......@@ -1363,6 +1372,7 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
*/
protected Class<?> resolveBeanClass(final RootBeanDefinition mbd, String beanName, final Class<?>... typesToMatch)
throws CannotLoadBeanClassException {
try {
if (mbd.hasBeanClass()) {
return mbd.getBeanClass();
......
......@@ -1574,7 +1574,9 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
}
}
// Lenient fallback: dummy factory in case of original factory not found...
return new DefaultListableBeanFactory();
DefaultListableBeanFactory dummyFactory = new DefaultListableBeanFactory();
dummyFactory.serializationId = this.id;
return dummyFactory;
}
}
......
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
......@@ -28,6 +28,12 @@ import java.lang.annotation.Target;
* does not explicitly depend on another through properties or constructor arguments,
* but rather depends on the side effects of another bean's initialization.
*
* <p>A depends-on declaration can specify both an initialization-time dependency and,
* in the case of singleton beans only, a corresponding destruction-time dependency.
* Dependent beans that define a depends-on relationship with a given bean are destroyed
* first, prior to the given bean itself being destroyed. Thus, a depends-on declaration
* can also control shutdown order.
*
* <p>May be used on any class directly or indirectly annotated with
* {@link org.springframework.stereotype.Component} or on methods annotated
* with {@link Bean}.
......
......@@ -171,8 +171,23 @@ public class MethodValidationInterceptor implements MethodInterceptor {
private boolean isFactoryBeanMetadataMethod(Method method) {
Class<?> clazz = method.getDeclaringClass();
return ((clazz == FactoryBean.class || clazz == SmartFactoryBean.class) &&
!method.getName().equals("getObject"));
// Call from interface-based proxy handle, allowing for an efficient check?
if (clazz.isInterface()) {
return ((clazz == FactoryBean.class || clazz == SmartFactoryBean.class) &&
!method.getName().equals("getObject"));
}
// Call from CGLIB proxy handle, potentially implementing a FactoryBean method?
Class<?> factoryBeanType = null;
if (SmartFactoryBean.class.isAssignableFrom(clazz)) {
factoryBeanType = SmartFactoryBean.class;
}
else if (FactoryBean.class.isAssignableFrom(clazz)) {
factoryBeanType = FactoryBean.class;
}
return (factoryBeanType != null && !method.getName().equals("getObject") &&
ClassUtils.hasMethod(factoryBeanType, method.getName(), method.getParameterTypes()));
}
/**
......
......@@ -161,7 +161,7 @@ public class EnableAsyncTests {
Object bean = ctx.getBean(CustomAsyncBean.class);
assertTrue(AopUtils.isAopProxy(bean));
boolean isAsyncAdvised = false;
for (Advisor advisor : ((Advised)bean).getAdvisors()) {
for (Advisor advisor : ((Advised) bean).getAdvisors()) {
if (advisor instanceof AsyncAnnotationAdvisor) {
isAsyncAdvised = true;
break;
......@@ -365,7 +365,8 @@ public class EnableAsyncTests {
@EnableAsync
static class AsyncConfigWithMockito {
@Bean @Lazy
@Bean
@Lazy
public AsyncBean asyncBean() {
return Mockito.mock(AsyncBean.class);
}
......
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
......@@ -23,28 +23,29 @@ import javax.naming.NamingException;
import org.springframework.jndi.JndiTemplate;
/**
* Simple extension of the JndiTemplate class that always returns
* a given object. Very useful for testing. Effectively a mock object.
* Simple extension of the JndiTemplate class that always returns a given object.
*
* <p>Very useful for testing. Effectively a mock object.
*
* @author Rod Johnson
* @author Juergen Hoeller
*/
public class ExpectedLookupTemplate extends JndiTemplate {
private final Map<String, Object> jndiObjects = new ConcurrentHashMap<String, Object>();
private final Map<String, Object> jndiObjects = new ConcurrentHashMap<String, Object>(16);
/**
* Construct a new JndiTemplate that will always return given objects
* for given names. To be populated through {@code addObject} calls.
* Construct a new JndiTemplate that will always return given objects for
* given names. To be populated through {@code addObject} calls.
* @see #addObject(String, Object)
*/
public ExpectedLookupTemplate() {
}
/**
* Construct a new JndiTemplate that will always return the
* given object, but honour only requests for the given name.
* Construct a new JndiTemplate that will always return the given object,
* but honour only requests for the given name.
* @param name the name the client is expected to look up
* @param object the object that will be returned
*/
......@@ -54,8 +55,7 @@ public class ExpectedLookupTemplate extends JndiTemplate {
/**
* Add the given object to the list of JNDI objects that this
* template will expose.
* Add the given object to the list of JNDI objects that this template will expose.
* @param name the name the client is expected to look up
* @param object the object that will be returned
*/
......@@ -63,11 +63,10 @@ public class ExpectedLookupTemplate extends JndiTemplate {
this.jndiObjects.put(name, object);
}
/**
* If the name is the expected name specified in the constructor,
* return the object provided in the constructor. If the name is
* unexpected, a respective NamingException gets thrown.
* If the name is the expected name specified in the constructor, return the
* object provided in the constructor. If the name is unexpected, a
* respective NamingException gets thrown.
*/
@Override
public Object lookup(String name) throws NamingException {
......
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2018 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,6 +26,7 @@ import javax.naming.spi.NamingManager;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
/**
......@@ -35,13 +36,14 @@ import org.springframework.util.ClassUtils;
* configure JNDI appropriately, so that {@code new InitialContext()}
* will expose the required objects. Also usable for standalone applications,
* e.g. for binding a JDBC DataSource to a well-known JNDI location, to be
* able to use traditional J2EE data access code outside of a J2EE container.
* able to use traditional Java EE data access code outside of a Java EE
* container.
*
* <p>There are various choices for DataSource implementations:
* <ul>
* <li>{@code SingleConnectionDataSource} (using the same Connection for all getConnection calls)
* <li>{@code DriverManagerDataSource} (creating a new Connection on each getConnection call)
* <li>Apache's Jakarta Commons DBCP offers {@code org.apache.commons.dbcp.BasicDataSource} (a real pool)
* <li>Apache's Commons DBCP offers {@code org.apache.commons.dbcp.BasicDataSource} (a real pool)
* </ul>
*
* <p>Typical usage in bootstrap code:
......@@ -98,7 +100,7 @@ public class SimpleNamingContextBuilder implements InitialContextFactoryBuilder
/**
* If no SimpleNamingContextBuilder is already configuring JNDI,
* create and activate one. Otherwise take the existing activate
* create and activate one. Otherwise take the existing activated
* SimpleNamingContextBuilder, clear it and return it.
* <p>This is mainly intended for test suites that want to
* reinitialize JNDI bindings from scratch repeatedly.
......@@ -137,12 +139,10 @@ public class SimpleNamingContextBuilder implements InitialContextFactoryBuilder
logger.info("Activating simple JNDI environment");
synchronized (initializationLock) {
if (!initialized) {
if (NamingManager.hasInitialContextFactoryBuilder()) {
throw new IllegalStateException(
Assert.state(!NamingManager.hasInitialContextFactoryBuilder(),
"Cannot activate SimpleNamingContextBuilder: there is already a JNDI provider registered. " +
"Note that JNDI is a JVM-wide service, shared at the JVM system class loader level, " +
"with no reset option. As a consequence, a JNDI provider must only be registered once per JVM.");
}
NamingManager.setInitialContextFactoryBuilder(this);
initialized = true;
}
......
......@@ -123,7 +123,16 @@ public class MethodValidationTests {
@Test
public void testLazyValidatorForMethodValidation() {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(
LazyMethodValidationConfig.class, CustomValidatorBean.class, MyValidBean.class, MyValidFactoryBean.class);
LazyMethodValidationConfig.class, CustomValidatorBean.class,
MyValidBean.class, MyValidFactoryBean.class);
ctx.getBeansOfType(MyValidInterface.class).values().forEach(bean -> bean.myValidMethod("value", 5));
}
@Test
public void testLazyValidatorForMethodValidationWithProxyTargetClass() {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(
LazyMethodValidationConfigWithProxyTargetClass.class, CustomValidatorBean.class,
MyValidBean.class, MyValidFactoryBean.class);
ctx.getBeansOfType(MyValidInterface.class).values().forEach(bean -> bean.myValidMethod("value", 5));
}
......@@ -223,4 +232,17 @@ public class MethodValidationTests {
}
}
@Configuration
public static class LazyMethodValidationConfigWithProxyTargetClass {
@Bean
public static MethodValidationPostProcessor methodValidationPostProcessor(@Lazy Validator validator) {
MethodValidationPostProcessor postProcessor = new MethodValidationPostProcessor();
postProcessor.setValidator(validator);
postProcessor.setProxyTargetClass(true);
return postProcessor;
}
}
}
/**
* Spring's repackaging of
* <a href="http://asm.ow2.org">ASM</a>
* (for internal use only).
* <a href="http://asm.ow2.org">ASM 6.0</a>
* (with Spring-specific patches; for internal use only).
*
* <p>This repackaging technique avoids any potential conflicts with
* dependencies on ASM at the application level or from third-party
......
/**
* Spring's repackaging of
* <a href="http://cglib.sourceforge.net">CGLIB</a>
* (for internal use only).
* <a href="https://github.com/cglib/cglib">CGLIB 3.2</a>
* (with Spring naming strategy; for internal use only).
*
* <p>This repackaging technique avoids any potential conflicts with
* dependencies on CGLIB at the application level or from third-party
......
/*
* Copyright 2002-2017 the original author or authors.
* Copyright 2002-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
......@@ -17,6 +17,7 @@
package org.springframework.core.io.support;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
......@@ -170,7 +171,7 @@ import org.springframework.util.StringUtils;
* @author Colin Sampaleanu
* @author Marius Bogoevici
* @author Costin Leau
* @author Phil Webb
* @author Phillip Webb
* @since 1.0.2
* @see #CLASSPATH_ALL_URL_PREFIX
* @see org.springframework.util.AntPathMatcher
......@@ -716,10 +717,16 @@ public class PathMatchingResourcePatternResolver implements ResourcePatternResol
try {
rootDir = rootDirResource.getFile().getAbsoluteFile();
}
catch (IOException ex) {
catch (FileNotFoundException ex) {
if (logger.isInfoEnabled()) {
logger.info("Cannot search for matching files underneath " + rootDirResource +
" in the file system: " + ex.getMessage());
}
return Collections.emptySet();
}
catch (Exception ex) {
if (logger.isWarnEnabled()) {
logger.warn("Cannot search for matching files underneath " + rootDirResource +
" because it does not correspond to a directory in the file system", ex);
logger.warn("Failed to resolve " + rootDirResource + " in the file system: " + ex);
}
return Collections.emptySet();
}
......
......@@ -57,14 +57,14 @@ import org.springframework.util.StringUtils;
*/
public abstract class SpringFactoriesLoader {
private static final Log logger = LogFactory.getLog(SpringFactoriesLoader.class);
/**
* The location to look for factories.
* <p>Can be present in multiple JAR files.
*/
public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";
private static final Log logger = LogFactory.getLog(SpringFactoriesLoader.class);
/**
* Load and instantiate the factory implementations of the given type from
......@@ -74,9 +74,9 @@ public abstract class SpringFactoriesLoader {
* to obtain all registered factory names.
* @param factoryClass the interface or abstract class representing the factory
* @param classLoader the ClassLoader to use for loading (can be {@code null} to use the default)
* @see #loadFactoryNames
* @throws IllegalArgumentException if any factory implementation class cannot
* be loaded or if an error occurs while instantiating any factory
* @see #loadFactoryNames
*/
public static <T> List<T> loadFactories(Class<T> factoryClass, ClassLoader classLoader) {
Assert.notNull(factoryClass, "'factoryClass' must not be null");
......@@ -103,8 +103,8 @@ public abstract class SpringFactoriesLoader {
* @param factoryClass the interface or abstract class representing the factory
* @param classLoader the ClassLoader to use for loading resources; can be
* {@code null} to use the default
* @see #loadFactories
* @throws IllegalArgumentException if an error occurs while loading factory names
* @see #loadFactories
*/
public static List<String> loadFactoryNames(Class<?> factoryClass, ClassLoader classLoader) {
String factoryClassName = factoryClass.getName();
......@@ -115,14 +115,16 @@ public abstract class SpringFactoriesLoader {
while (urls.hasMoreElements()) {
URL url = urls.nextElement();
Properties properties = PropertiesLoaderUtils.loadProperties(new UrlResource(url));
String factoryClassNames = properties.getProperty(factoryClassName);
result.addAll(Arrays.asList(StringUtils.commaDelimitedListToStringArray(factoryClassNames)));
String propertyValue = properties.getProperty(factoryClassName);
for (String factoryName : StringUtils.commaDelimitedListToStringArray(propertyValue)) {
result.add(factoryName.trim());
}
}
return result;
}
catch (IOException ex) {
throw new IllegalArgumentException("Unable to load [" + factoryClass.getName() +
"] factories from location [" + FACTORIES_RESOURCE_LOCATION + "]", ex);
throw new IllegalArgumentException("Unable to load factories from location [" +
FACTORIES_RESOURCE_LOCATION + "]", ex);
}
}
......
/**
* Spring's repackaging of
* <a href="http://objenesis.org">Objenesis 2.1</a>
* (for internal use only).
* <a href="http://objenesis.org">Objenesis 2.6</a>
* (with SpringObjenesis entry point; for internal use only).
*
* <p>This repackaging technique avoids any potential conflicts with
* dependencies on different Objenesis versions at the application
......
/*
* Copyright 2002-2017 the original author or authors.
* Copyright 2002-2018 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.
......@@ -367,7 +367,7 @@ public class FastByteArrayOutputStream extends OutputStream {
else {
if (this.nextIndexInCurrentBuffer < this.currentBufferLength) {
this.totalBytesRead++;
return this.currentBuffer[this.nextIndexInCurrentBuffer++];
return this.currentBuffer[this.nextIndexInCurrentBuffer++] & 0xFF;
}
else {
if (this.buffersIterator.hasNext()) {
......@@ -487,7 +487,7 @@ public class FastByteArrayOutputStream extends OutputStream {
/**
* Update the message digest with the remaining bytes in this stream.
* @param messageDigest The message digest to update
* @param messageDigest the message digest to update
*/
@Override
public void updateMessageDigest(MessageDigest messageDigest) {
......@@ -497,7 +497,7 @@ public class FastByteArrayOutputStream extends OutputStream {
/**
* Update the message digest with the next len bytes in this stream.
* Avoids creating new byte arrays and use internal buffers for performance.
* @param messageDigest The message digest to update
* @param messageDigest the message digest to update
* @param len how many bytes to read from this stream and use to update the message digest
*/
@Override
......
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
......@@ -30,7 +30,7 @@ public interface MultiValueMap<K, V> extends Map<K, List<V>> {
/**
* Return the first value for the given key.
* @param key the key
* @return the first value for the specified key, or {@code null}
* @return the first value for the specified key, or {@code null} if none
*/
V getFirst(K key);
......@@ -55,7 +55,7 @@ public interface MultiValueMap<K, V> extends Map<K, List<V>> {
void setAll(Map<K, V> values);
/**
* Returns the first values contained in this {@code MultiValueMap}.
* Return a {@code Map} with the first values contained in this {@code MultiValueMap}.
* @return a single value representation of this map
*/
Map<K, V> toSingleValueMap();
......
/*
* Copyright 2002-2017 the original author or authors.
* Copyright 2002-2018 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.
......@@ -170,7 +170,7 @@ public abstract class ObjectUtils {
/**
* Check whether the given array of enum constants contains a constant with the given name,
* ignoring case when determining a match.
* @param enumValues the enum values to check, typically the product of a call to MyEnum.values()
* @param enumValues the enum values to check, typically obtained via {@code MyEnum.values()}
* @param constant the constant name to find (must not be null or empty string)
* @return whether the constant has been found in the given array
*/
......@@ -180,15 +180,14 @@ public abstract class ObjectUtils {
/**
* Check whether the given array of enum constants contains a constant with the given name.
* @param enumValues the enum values to check, typically the product of a call to MyEnum.values()
* @param enumValues the enum values to check, typically obtained via {@code MyEnum.values()}
* @param constant the constant name to find (must not be null or empty string)
* @param caseSensitive whether case is significant in determining a match
* @return whether the constant has been found in the given array
*/
public static boolean containsConstant(Enum<?>[] enumValues, String constant, boolean caseSensitive) {
for (Enum<?> candidate : enumValues) {
if (caseSensitive ?
candidate.toString().equals(constant) :