CollectionUtils.lastElement for common Set/List extraction

Issue: SPR-16374
This commit is contained in:
Juergen Hoeller 2018-01-12 18:23:52 +01:00
parent 13a8f90e08
commit 06e6386dc9
7 changed files with 75 additions and 33 deletions

View File

@ -1,5 +1,5 @@
/* /*
* 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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -712,8 +712,7 @@ class ConfigurationClassParser {
@Override @Override
@Nullable @Nullable
public AnnotationMetadata getImportingClassFor(String importedClass) { public AnnotationMetadata getImportingClassFor(String importedClass) {
List<AnnotationMetadata> list = this.imports.get(importedClass); return CollectionUtils.lastElement(this.imports.get(importedClass));
return (!CollectionUtils.isEmpty(list) ? list.get(list.size() - 1) : null);
} }
@Override @Override

View File

@ -1,5 +1,5 @@
/* /*
* 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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -24,6 +24,8 @@ import joptsimple.OptionSet;
import joptsimple.OptionSpec; import joptsimple.OptionSpec;
import org.springframework.lang.Nullable; import org.springframework.lang.Nullable;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
/** /**
* {@link CommandLinePropertySource} implementation backed by a JOpt {@link OptionSet}. * {@link CommandLinePropertySource} implementation backed by a JOpt {@link OptionSet}.
@ -86,13 +88,13 @@ public class JOptCommandLinePropertySource extends CommandLinePropertySource<Opt
public String[] getPropertyNames() { public String[] getPropertyNames() {
List<String> names = new ArrayList<>(); List<String> names = new ArrayList<>();
for (OptionSpec<?> spec : this.source.specs()) { for (OptionSpec<?> spec : this.source.specs()) {
List<String> aliases = new ArrayList<>(spec.options()); String lastOption = CollectionUtils.lastElement(spec.options());
if (!aliases.isEmpty()) { if (lastOption != null) {
// Only the longest name is used for enumerating // Only the longest name is used for enumerating
names.add(aliases.get(aliases.size() - 1)); names.add(lastOption);
} }
} }
return names.toArray(new String[names.size()]); return StringUtils.toStringArray(names);
} }
@Override @Override

View File

@ -1,5 +1,5 @@
/* /*
* 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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -29,6 +29,7 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Properties; import java.util.Properties;
import java.util.Set; import java.util.Set;
import java.util.SortedSet;
import org.springframework.lang.Nullable; import org.springframework.lang.Nullable;
@ -312,6 +313,48 @@ public abstract class CollectionUtils {
return candidate; return candidate;
} }
/**
* Retrieve the last element of the given Set, using {@link SortedSet#last()}
* or otherwise iterating over all elements (assuming a linked set).
* @param set the Set to check (may be {@code null} or empty)
* @return the last element, or {@code null} if none
* @since 5.0.3
* @see SortedSet
* @see LinkedHashMap#keySet()
* @see java.util.LinkedHashSet
*/
@Nullable
public static <T> T lastElement(@Nullable Set<T> set) {
if (isEmpty(set)) {
return null;
}
if (set instanceof SortedSet) {
return ((SortedSet<T>) set).last();
}
// Full iteration necessary...
Iterator<T> it = set.iterator();
T last = null;
while (it.hasNext()) {
last = it.next();
}
return last;
}
/**
* Retrieve the last element of the given List, accessing the highest index.
* @param list the List to check (may be {@code null} or empty)
* @return the last element, or {@code null} if none
* @since 5.0.3
*/
@Nullable
public static <T> T lastElement(@Nullable List<T> list) {
if (isEmpty(list)) {
return null;
}
return list.get(list.size() - 1);
}
/** /**
* Marshal the elements from the given enumeration into an array of the given type. * Marshal the elements from the given enumeration into an array of the given type.
* Enumeration elements must be assignable to the type of the given array. The array * Enumeration elements must be assignable to the type of the given array. The array

View File

@ -1,5 +1,5 @@
/* /*
* 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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -26,6 +26,7 @@ import org.springframework.asm.ClassWriter;
import org.springframework.asm.MethodVisitor; import org.springframework.asm.MethodVisitor;
import org.springframework.asm.Opcodes; import org.springframework.asm.Opcodes;
import org.springframework.lang.Nullable; import org.springframework.lang.Nullable;
import org.springframework.util.CollectionUtils;
/** /**
* Manages the class being generated by the compilation process. * Manages the class being generated by the compilation process.
@ -153,10 +154,7 @@ public class CodeFlow implements Opcodes {
*/ */
@Nullable @Nullable
public String lastDescriptor() { public String lastDescriptor() {
if (this.compilationScopes.peek().isEmpty()) { return CollectionUtils.lastElement(this.compilationScopes.peek());
return null;
}
return this.compilationScopes.peek().get(this.compilationScopes.peek().size() - 1);
} }
/** /**

View File

@ -1,5 +1,5 @@
/* /*
* 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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -31,6 +31,7 @@ import org.springframework.expression.spel.SpelEvaluationException;
import org.springframework.expression.spel.SpelMessage; import org.springframework.expression.spel.SpelMessage;
import org.springframework.util.Assert; import org.springframework.util.Assert;
import org.springframework.util.ClassUtils; import org.springframework.util.ClassUtils;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils; import org.springframework.util.ObjectUtils;
/** /**
@ -160,7 +161,7 @@ public class Selection extends SpelNodeImpl {
} }
if (this.variant == LAST) { if (this.variant == LAST) {
return new ValueRef.TypedValueHolderValueRef(new TypedValue(result.get(result.size() - 1)), this); return new ValueRef.TypedValueHolderValueRef(new TypedValue(CollectionUtils.lastElement(result)), this);
} }
if (operand instanceof Iterable) { if (operand instanceof Iterable) {

View File

@ -1,5 +1,5 @@
/* /*
* 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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -16,12 +16,11 @@
package org.springframework.web.method.annotation; package org.springframework.web.method.annotation;
import java.util.ArrayList;
import org.springframework.core.MethodParameter; import org.springframework.core.MethodParameter;
import org.springframework.lang.Nullable; import org.springframework.lang.Nullable;
import org.springframework.ui.ModelMap; import org.springframework.ui.ModelMap;
import org.springframework.util.Assert; import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import org.springframework.validation.BindingResult; import org.springframework.validation.BindingResult;
import org.springframework.validation.Errors; import org.springframework.validation.Errors;
import org.springframework.web.bind.support.WebDataBinderFactory; import org.springframework.web.bind.support.WebDataBinderFactory;
@ -38,6 +37,7 @@ import org.springframework.web.method.support.ModelAndViewContainer;
* {@link BindingResult}. * {@link BindingResult}.
* *
* @author Rossen Stoyanchev * @author Rossen Stoyanchev
* @author Juergen Hoeller
* @since 3.1 * @since 3.1
*/ */
public class ErrorsMethodArgumentResolver implements HandlerMethodArgumentResolver { public class ErrorsMethodArgumentResolver implements HandlerMethodArgumentResolver {
@ -58,18 +58,15 @@ public class ErrorsMethodArgumentResolver implements HandlerMethodArgumentResolv
"Errors/BindingResult argument only supported on regular handler methods"); "Errors/BindingResult argument only supported on regular handler methods");
ModelMap model = mavContainer.getModel(); ModelMap model = mavContainer.getModel();
if (model.size() > 0) { String lastKey = CollectionUtils.lastElement(model.keySet());
int lastIndex = model.size()-1; if (lastKey != null && lastKey.startsWith(BindingResult.MODEL_KEY_PREFIX)) {
String lastKey = new ArrayList<>(model.keySet()).get(lastIndex); return model.get(lastKey);
if (lastKey.startsWith(BindingResult.MODEL_KEY_PREFIX)) {
return model.get(lastKey);
}
} }
throw new IllegalStateException( throw new IllegalStateException(
"An Errors/BindingResult argument is expected to be declared immediately after " + "An Errors/BindingResult argument is expected to be declared immediately after " +
"the model attribute, the @RequestBody or the @RequestPart arguments " + "the model attribute, the @RequestBody or the @RequestPart arguments " +
"to which they apply: " + parameter.getMethod()); "to which they apply: " + parameter.getMethod());
} }
} }

View File

@ -1,5 +1,5 @@
/* /*
* 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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -35,7 +35,7 @@ import static org.junit.Assert.*;
* *
* @author Rossen Stoyanchev * @author Rossen Stoyanchev
*/ */
public class ErrorsMethodHandlerArgumentResolverTests { public class ErrorsMethodArgumentResolverTests {
private final ErrorsMethodArgumentResolver resolver = new ErrorsMethodArgumentResolver(); private final ErrorsMethodArgumentResolver resolver = new ErrorsMethodArgumentResolver();
@ -45,15 +45,17 @@ public class ErrorsMethodHandlerArgumentResolverTests {
private NativeWebRequest webRequest; private NativeWebRequest webRequest;
@Before @Before
public void setUp() throws Exception { public void setup() throws Exception {
paramErrors = new MethodParameter(getClass().getDeclaredMethod("handle", Errors.class), 0); paramErrors = new MethodParameter(getClass().getDeclaredMethod("handle", Errors.class), 0);
bindingResult = new WebDataBinder(new Object(), "attr").getBindingResult(); bindingResult = new WebDataBinder(new Object(), "attr").getBindingResult();
webRequest = new ServletWebRequest(new MockHttpServletRequest()); webRequest = new ServletWebRequest(new MockHttpServletRequest());
} }
@Test @Test
public void supports() throws Exception { public void supports() {
resolver.supportsParameter(paramErrors); resolver.supportsParameter(paramErrors);
} }
@ -68,7 +70,6 @@ public class ErrorsMethodHandlerArgumentResolverTests {
mavContainer.addAllAttributes(bindingResult.getModel()); mavContainer.addAllAttributes(bindingResult.getModel());
Object actual = resolver.resolveArgument(paramErrors, mavContainer, webRequest, null); Object actual = resolver.resolveArgument(paramErrors, mavContainer, webRequest, null);
assertSame(actual, bindingResult); assertSame(actual, bindingResult);
} }
@ -86,8 +87,9 @@ public class ErrorsMethodHandlerArgumentResolverTests {
resolver.resolveArgument(paramErrors, new ModelAndViewContainer(), webRequest, null); resolver.resolveArgument(paramErrors, new ModelAndViewContainer(), webRequest, null);
} }
@SuppressWarnings("unused") @SuppressWarnings("unused")
private void handle(Errors errors) { private void handle(Errors errors) {
} }
} }