Browse Source

Polishing

pull/33883/head
Juergen Hoeller 1 year ago
parent
commit
37b110a181
  1. 5
      spring-core/src/main/java/org/springframework/aot/generate/GeneratedFiles.java
  2. 15
      spring-core/src/main/java/org/springframework/aot/hint/annotation/RegisterReflection.java
  3. 21
      spring-core/src/main/java/org/springframework/aot/hint/annotation/RegisterReflectionReflectiveProcessor.java
  4. 6
      spring-core/src/main/java/org/springframework/core/env/ConfigurablePropertyResolver.java
  5. 27
      spring-core/src/main/java/org/springframework/core/io/buffer/JettyDataBuffer.java
  6. 1
      spring-core/src/main/java/org/springframework/core/io/buffer/JettyDataBufferFactory.java
  7. 4
      spring-core/src/main/java/org/springframework/lang/CheckReturnValue.java
  8. 7
      spring-core/src/main/java/org/springframework/lang/Contract.java
  9. 3
      spring-core/src/main/java/org/springframework/util/ClassUtils.java
  10. 2
      spring-core/src/main/java/org/springframework/util/CollectionUtils.java
  11. 2
      spring-core/src/main/java/org/springframework/util/CompositeCollection.java
  12. 1
      spring-core/src/main/java/org/springframework/util/CompositeMap.java
  13. 20
      spring-core/src/main/java/org/springframework/util/CompositeSet.java
  14. 4
      spring-core/src/main/java/org/springframework/util/FilteredCollection.java
  15. 3
      spring-core/src/main/java/org/springframework/util/FilteredIterator.java
  16. 3
      spring-core/src/main/java/org/springframework/util/FilteredMap.java
  17. 22
      spring-core/src/main/java/org/springframework/util/FilteredSet.java
  18. 67
      spring-core/src/main/java/org/springframework/util/MultiToSingleValueMapAdapter.java
  19. 11
      spring-core/src/main/java/org/springframework/util/MultiValueMap.java
  20. 10
      spring-core/src/main/java/org/springframework/util/PlaceholderParser.java
  21. 2
      spring-core/src/main/java/org/springframework/util/PlaceholderResolutionException.java
  22. 24
      spring-core/src/main/java/org/springframework/util/SingleToMultiValueMapAdapter.java
  23. 11
      spring-core/src/main/java/org/springframework/util/unit/DataSize.java
  24. 20
      spring-core/src/test/java/org/springframework/aot/hint/annotation/RegisterReflectionReflectiveProcessorTests.java

5
spring-core/src/main/java/org/springframework/aot/generate/GeneratedFiles.java

@ -181,6 +181,7 @@ public interface GeneratedFiles {
*/ */
void handleFile(Kind kind, String path, ThrowingConsumer<FileHandler> handler); void handleFile(Kind kind, String path, ThrowingConsumer<FileHandler> handler);
private static String getClassNamePath(String className) { private static String getClassNamePath(String className) {
Assert.hasLength(className, "'className' must not be empty"); Assert.hasLength(className, "'className' must not be empty");
validatePackage(ClassUtils.getPackageName(className), className); validatePackage(ClassUtils.getPackageName(className), className);
@ -232,13 +233,12 @@ public interface GeneratedFiles {
* generated using CGLIB. * generated using CGLIB.
*/ */
CLASS CLASS
} }
/** /**
* Provide access to a particular file and offer convenient methods to retrieve, * Provide access to a particular file and offer convenient methods to retrieve,
* save, or override its content. * save, or override its content.
*
* @since 6.2 * @since 6.2
*/ */
abstract class FileHandler { abstract class FileHandler {
@ -292,7 +292,6 @@ public interface GeneratedFiles {
} }
protected abstract void copy(InputStreamSource content, boolean override); protected abstract void copy(InputStreamSource content, boolean override);
} }
} }

15
spring-core/src/main/java/org/springframework/aot/hint/annotation/RegisterReflection.java

@ -48,7 +48,8 @@ import org.springframework.aot.hint.MemberCategory;
* packages can use this annotation as well. * packages can use this annotation as well.
* *
* <p>To register reflection hints for the type itself, only member categories * <p>To register reflection hints for the type itself, only member categories
* should be specified:<pre><code class="java"> * should be specified:
* <pre><code class="java">
* &#064;Component * &#064;Component
* &#064;RegisterReflection(memberCategories = INVOKE_PUBLIC_METHODS) * &#064;RegisterReflection(memberCategories = INVOKE_PUBLIC_METHODS)
* class MyComponent { * class MyComponent {
@ -56,7 +57,8 @@ import org.springframework.aot.hint.MemberCategory;
* }</code></pre> * }</code></pre>
* *
* <p>Reflection hints can be registered from a method. In this case, at least * <p>Reflection hints can be registered from a method. In this case, at least
* one target class should be specified:<pre><code class="java"> * one target class should be specified:
* <pre><code class="java">
* class MyProcessor { * class MyProcessor {
* *
* &#064;RegisterReflection(classes = CustomerEntry.class, memberCategories = PUBLIC_FIELDS) * &#064;RegisterReflection(classes = CustomerEntry.class, memberCategories = PUBLIC_FIELDS)
@ -81,11 +83,10 @@ public @interface RegisterReflection {
/** /**
* Classes for which reflection hints should be registered. Consider using * Classes for which reflection hints should be registered. Consider using
* {@link #classNames()} for classes that are not public in the current * {@link #classNames()} for classes that are not public in the current scope.
* scope. If both {@code classes} and {@code classNames} are specified, they * If both {@code classes} and {@code classNames} are specified, they are
* are merged in a single set. * merged into a single set.
* <p> * <p>By default, the annotated type is the target of the registration. When
* By default, the annotated type is the target of the registration. When
* placed on a method, at least one class must be specified. * placed on a method, at least one class must be specified.
* @see #classNames() * @see #classNames()
*/ */

21
spring-core/src/main/java/org/springframework/aot/hint/annotation/RegisterReflectionReflectiveProcessor.java

@ -45,12 +45,11 @@ public class RegisterReflectionReflectiveProcessor implements ReflectiveProcesso
private static final Log logger = LogFactory.getLog(RegisterReflectionReflectiveProcessor.class); private static final Log logger = LogFactory.getLog(RegisterReflectionReflectiveProcessor.class);
@Override @Override
public final void registerReflectionHints(ReflectionHints hints, AnnotatedElement element) { public final void registerReflectionHints(ReflectionHints hints, AnnotatedElement element) {
RegisterReflection annotation = AnnotatedElementUtils.getMergedAnnotation( RegisterReflection annotation = AnnotatedElementUtils.getMergedAnnotation(element, RegisterReflection.class);
element, RegisterReflection.class); Assert.notNull(annotation, () -> "Element must be annotated with @RegisterReflection: " + element);
Assert.notNull(annotation, "Element must be annotated with @" + RegisterReflection.class.getSimpleName()
+ ": " + element);
ReflectionRegistration registration = parse(element, annotation); ReflectionRegistration registration = parse(element, annotation);
registerReflectionHints(hints, registration); registerReflectionHints(hints, registration);
} }
@ -65,12 +64,10 @@ public class RegisterReflectionReflectiveProcessor implements ReflectiveProcesso
allClassNames.add(clazz); allClassNames.add(clazz);
} }
else { else {
throw new IllegalStateException("At least one class must be specified, " throw new IllegalStateException("At least one class must be specified: " + element);
+ "could not detect target from '" + element + "'");
} }
} }
return new ReflectionRegistration(allClassNames.toArray(new Class<?>[0]), return new ReflectionRegistration(allClassNames.toArray(new Class<?>[0]), annotation.memberCategories());
annotation.memberCategories());
} }
protected void registerReflectionHints(ReflectionHints hints, ReflectionRegistration registration) { protected void registerReflectionHints(ReflectionHints hints, ReflectionRegistration registration) {
@ -89,11 +86,15 @@ public class RegisterReflectionReflectiveProcessor implements ReflectiveProcesso
return ClassUtils.forName(className, getClass().getClassLoader()); return ClassUtils.forName(className, getClass().getClassLoader());
} }
catch (Exception ex) { catch (Exception ex) {
logger.warn("Ignoring '" + className + "': " + ex.getMessage()); if (logger.isWarnEnabled()) {
logger.warn("Ignoring '" + className + "': " + ex);
}
return null; return null;
} }
} }
protected record ReflectionRegistration(Class<?>[] classes, MemberCategory[] memberCategories) {}
protected record ReflectionRegistration(Class<?>[] classes, MemberCategory[] memberCategories) {
}
} }

6
spring-core/src/main/java/org/springframework/core/env/ConfigurablePropertyResolver.java vendored

@ -26,6 +26,7 @@ import org.springframework.lang.Nullable;
* used when converting property values from one type to another. * used when converting property values from one type to another.
* *
* @author Chris Beams * @author Chris Beams
* @author Stephane Nicoll
* @since 3.1 * @since 3.1
*/ */
public interface ConfigurablePropertyResolver extends PropertyResolver { public interface ConfigurablePropertyResolver extends PropertyResolver {
@ -75,9 +76,8 @@ public interface ConfigurablePropertyResolver extends PropertyResolver {
void setValueSeparator(@Nullable String valueSeparator); void setValueSeparator(@Nullable String valueSeparator);
/** /**
* Specify the escape character to use to ignore placeholder prefix * Specify the escape character to use to ignore placeholder prefix or
* or value separator, or {@code null} if no escaping should take * value separator, or {@code null} if no escaping should take place.
* place.
* @since 6.2 * @since 6.2
*/ */
void setEscapeCharacter(@Nullable Character escapeCharacter); void setEscapeCharacter(@Nullable Character escapeCharacter);

27
spring-core/src/main/java/org/springframework/core/io/buffer/JettyDataBuffer.java

@ -67,6 +67,7 @@ public final class JettyDataBuffer implements PooledDataBuffer {
this.chunk = null; this.chunk = null;
} }
@Override @Override
public boolean isAllocated() { public boolean isAllocated() {
return this.refCount.get() > 0; return this.refCount.get() > 0;
@ -74,14 +75,7 @@ public final class JettyDataBuffer implements PooledDataBuffer {
@Override @Override
public PooledDataBuffer retain() { public PooledDataBuffer retain() {
int result = this.refCount.updateAndGet(c -> { int result = this.refCount.updateAndGet(c -> (c != 0 ? c + 1 : 0));
if (c != 0) {
return c + 1;
}
else {
return 0;
}
});
if (result != 0 && this.chunk != null) { if (result != 0 && this.chunk != null) {
this.chunk.retain(); this.chunk.retain();
} }
@ -107,7 +101,7 @@ public final class JettyDataBuffer implements PooledDataBuffer {
return this.chunk.release(); return this.chunk.release();
} }
else { else {
return result == 0; return (result == 0);
} }
} }
@ -116,6 +110,7 @@ public final class JettyDataBuffer implements PooledDataBuffer {
return this.bufferFactory; return this.bufferFactory;
} }
// delegation // delegation
@Override @Override
@ -305,15 +300,16 @@ public final class JettyDataBuffer implements PooledDataBuffer {
return this.delegate.toString(index, length, charset); return this.delegate.toString(index, length, charset);
} }
@Override @Override
public int hashCode() { public boolean equals(Object other) {
return this.delegate.hashCode(); return (this == other || (other instanceof JettyDataBuffer otherBuffer &&
this.delegate.equals(otherBuffer.delegate)));
} }
@Override @Override
public boolean equals(Object o) { public int hashCode() {
return this == o || (o instanceof JettyDataBuffer other && return this.delegate.hashCode();
this.delegate.equals(other.delegate));
} }
@Override @Override
@ -322,13 +318,13 @@ public final class JettyDataBuffer implements PooledDataBuffer {
readPosition(), writePosition(), capacity()); readPosition(), writePosition(), capacity());
} }
private static final class JettyByteBufferIterator implements ByteBufferIterator { private static final class JettyByteBufferIterator implements ByteBufferIterator {
private final ByteBufferIterator delegate; private final ByteBufferIterator delegate;
private final Content.Chunk chunk; private final Content.Chunk chunk;
public JettyByteBufferIterator(ByteBufferIterator delegate, Content.Chunk chunk) { public JettyByteBufferIterator(ByteBufferIterator delegate, Content.Chunk chunk) {
Assert.notNull(delegate, "Delegate must not be null"); Assert.notNull(delegate, "Delegate must not be null");
Assert.notNull(chunk, "Chunk must not be null"); Assert.notNull(chunk, "Chunk must not be null");
@ -338,7 +334,6 @@ public final class JettyDataBuffer implements PooledDataBuffer {
this.chunk.retain(); this.chunk.retain();
} }
@Override @Override
public void close() { public void close() {
this.delegate.close(); this.delegate.close();

1
spring-core/src/main/java/org/springframework/core/io/buffer/JettyDataBufferFactory.java

@ -105,4 +105,5 @@ public class JettyDataBufferFactory implements DataBufferFactory {
public boolean isDirect() { public boolean isDirect() {
return this.delegate.isDirect(); return this.delegate.isDirect();
} }
} }

4
spring-core/src/main/java/org/springframework/lang/CheckReturnValue.java

@ -23,8 +23,8 @@ import java.lang.annotation.Target;
/** /**
* Specifies that the method return value must be used. * Specifies that the method return value must be used.
* *
* <p>Inspired from {@code org.jetbrains.annotations.CheckReturnValue}, this variant * <p>Inspired by {@code org.jetbrains.annotations.CheckReturnValue}, this variant
* has been introduce in the {@code org.springframework.lang} package to avoid * has been introduced in the {@code org.springframework.lang} package to avoid
* requiring an extra dependency, while still following similar semantics. * requiring an extra dependency, while still following similar semantics.
* *
* <p>This annotation should not be used if the return value of the method * <p>This annotation should not be used if the return value of the method

7
spring-core/src/main/java/org/springframework/lang/Contract.java

@ -28,9 +28,9 @@ import java.lang.annotation.Target;
* just describes how the code works and doesn't add any functionality by means of * just describes how the code works and doesn't add any functionality by means of
* code generation. * code generation.
* *
* <p>Inspired from {@code org.jetbrains.annotations.Contract}, this variant has * <p>Inspired by {@code org.jetbrains.annotations.Contract}, this variant has
* been introduce in the {@code org.springframework.lang} package to avoid requiring * been introduced in the {@code org.springframework.lang} package to avoid
* an extra dependency, while still following the same semantics. * requiring an extra dependency, while still following the same semantics.
* *
* <p>Method contract has the following syntax: * <p>Method contract has the following syntax:
* <pre>{@code * <pre>{@code
@ -85,4 +85,5 @@ public @interface Contract {
* Contains the contract clauses describing causal relations between call arguments and the returned value. * Contains the contract clauses describing causal relations between call arguments and the returned value.
*/ */
String value() default ""; String value() default "";
} }

3
spring-core/src/main/java/org/springframework/util/ClassUtils.java

@ -1502,8 +1502,7 @@ public abstract class ClassUtils {
* (if there is one). For {@code toString()}, it may traverse as far as {@link Object}. * (if there is one). For {@code toString()}, it may traverse as far as {@link Object}.
* @param method the method to be invoked, potentially from an implementation class * @param method the method to be invoked, potentially from an implementation class
* @param targetClass the target class to invoke the method on, or {@code null} if unknown * @param targetClass the target class to invoke the method on, or {@code null} if unknown
* @return the corresponding publicly accessible method, or the original method if none * @return the corresponding publicly accessible method, or the original method if none found
* found
* @since 6.2 * @since 6.2
* @see #getInterfaceMethodIfPossible(Method, Class) * @see #getInterfaceMethodIfPossible(Method, Class)
* @see #getMostSpecificMethod(Method, Class) * @see #getMostSpecificMethod(Method, Class)

2
spring-core/src/main/java/org/springframework/util/CollectionUtils.java

@ -515,7 +515,6 @@ public abstract class CollectionUtils {
* Return a (partially unmodifiable) map that combines the provided two * Return a (partially unmodifiable) map that combines the provided two
* maps. Invoking {@link Map#put(Object, Object)} or {@link Map#putAll(Map)} * maps. Invoking {@link Map#put(Object, Object)} or {@link Map#putAll(Map)}
* on the returned map results in an {@link UnsupportedOperationException}. * on the returned map results in an {@link UnsupportedOperationException}.
*
* <p>In the case of a key collision, {@code first} takes precedence over * <p>In the case of a key collision, {@code first} takes precedence over
* {@code second}. In other words, entries in {@code second} with a key * {@code second}. In other words, entries in {@code second} with a key
* that is also mapped by {@code first} are effectively ignored. * that is also mapped by {@code first} are effectively ignored.
@ -535,7 +534,6 @@ public abstract class CollectionUtils {
* {@link UnsupportedOperationException} {@code putFunction} is * {@link UnsupportedOperationException} {@code putFunction} is
* {@code null}. The same applies to {@link Map#putAll(Map)} and * {@code null}. The same applies to {@link Map#putAll(Map)} and
* {@code putAllFunction}. * {@code putAllFunction}.
*
* <p>In the case of a key collision, {@code first} takes precedence over * <p>In the case of a key collision, {@code first} takes precedence over
* {@code second}. In other words, entries in {@code second} with a key * {@code second}. In other words, entries in {@code second} with a key
* that is also mapped by {@code first} are effectively ignored. * that is also mapped by {@code first} are effectively ignored.

2
spring-core/src/main/java/org/springframework/util/CompositeCollection.java

@ -43,6 +43,7 @@ class CompositeCollection<E> implements Collection<E> {
this.second = second; this.second = second;
} }
@Override @Override
public int size() { public int size() {
return this.first.size() + this.second.size(); return this.first.size() + this.second.size();
@ -160,4 +161,5 @@ class CompositeCollection<E> implements Collection<E> {
this.first.clear(); this.first.clear();
this.second.clear(); this.second.clear();
} }
} }

1
spring-core/src/main/java/org/springframework/util/CompositeMap.java

@ -186,4 +186,5 @@ final class CompositeMap<K, V> implements Map<K, V> {
sb.append(',').append(' '); sb.append(',').append(' ');
} }
} }
} }

20
spring-core/src/main/java/org/springframework/util/CompositeSet.java

@ -18,6 +18,8 @@ package org.springframework.util;
import java.util.Set; import java.util.Set;
import org.springframework.lang.Nullable;
/** /**
* Composite set that combines two other sets. This type is only exposed through * Composite set that combines two other sets. This type is only exposed through
* {@link CompositeMap#keySet()} and {@link CompositeMap#entrySet()}. * {@link CompositeMap#keySet()} and {@link CompositeMap#entrySet()}.
@ -34,24 +36,19 @@ final class CompositeSet<E> extends CompositeCollection<E> implements Set<E> {
@Override @Override
public boolean equals(Object obj) { public boolean equals(@Nullable Object other) {
if (obj == this) { if (this == other) {
return true; return true;
} }
else if (obj instanceof Set<?> set) { if (other instanceof Set<?> otherSet && size() == otherSet.size()) {
if (set.size() != size()) {
return false;
}
try { try {
return containsAll(set); return containsAll(otherSet);
} }
catch (ClassCastException | NullPointerException ignored) { catch (ClassCastException | NullPointerException ignored) {
return false; // fall through
} }
} }
else { return false;
return false;
}
} }
@Override @Override
@ -64,4 +61,5 @@ final class CompositeSet<E> extends CompositeCollection<E> implements Set<E> {
} }
return hashCode; return hashCode;
} }
} }

4
spring-core/src/main/java/org/springframework/util/FilteredCollection.java

@ -24,6 +24,7 @@ import java.util.function.Predicate;
/** /**
* Collection that filters out values that do not match a predicate. * Collection that filters out values that do not match a predicate.
* This type is used by {@link CompositeMap}. * This type is used by {@link CompositeMap}.
*
* @author Arjen Poutsma * @author Arjen Poutsma
* @since 6.2 * @since 6.2
* @param <E> the type of elements maintained by this collection * @param <E> the type of elements maintained by this collection
@ -38,11 +39,11 @@ class FilteredCollection<E> extends AbstractCollection<E> {
public FilteredCollection(Collection<E> delegate, Predicate<E> filter) { public FilteredCollection(Collection<E> delegate, Predicate<E> filter) {
Assert.notNull(delegate, "Delegate must not be null"); Assert.notNull(delegate, "Delegate must not be null");
Assert.notNull(filter, "Filter must not be null"); Assert.notNull(filter, "Filter must not be null");
this.delegate = delegate; this.delegate = delegate;
this.filter = filter; this.filter = filter;
} }
@Override @Override
public int size() { public int size() {
int size = 0; int size = 0;
@ -87,4 +88,5 @@ class FilteredCollection<E> extends AbstractCollection<E> {
public void clear() { public void clear() {
this.delegate.clear(); this.delegate.clear();
} }
} }

3
spring-core/src/main/java/org/springframework/util/FilteredIterator.java

@ -25,6 +25,7 @@ import org.springframework.lang.Nullable;
/** /**
* Iterator that filters out values that do not match a predicate. * Iterator that filters out values that do not match a predicate.
* This type is used by {@link CompositeMap}. * This type is used by {@link CompositeMap}.
*
* @author Arjen Poutsma * @author Arjen Poutsma
* @since 6.2 * @since 6.2
* @param <E> the type of elements returned by this iterator * @param <E> the type of elements returned by this iterator
@ -44,7 +45,6 @@ final class FilteredIterator<E> implements Iterator<E> {
public FilteredIterator(Iterator<E> delegate, Predicate<E> filter) { public FilteredIterator(Iterator<E> delegate, Predicate<E> filter) {
Assert.notNull(delegate, "Delegate must not be null"); Assert.notNull(delegate, "Delegate must not be null");
Assert.notNull(filter, "Filter must not be null"); Assert.notNull(filter, "Filter must not be null");
this.delegate = delegate; this.delegate = delegate;
this.filter = filter; this.filter = filter;
} }
@ -83,4 +83,5 @@ final class FilteredIterator<E> implements Iterator<E> {
} }
return false; return false;
} }
} }

3
spring-core/src/main/java/org/springframework/util/FilteredMap.java

@ -26,6 +26,7 @@ import org.springframework.lang.Nullable;
/** /**
* Map that filters out values that do not match a predicate. * Map that filters out values that do not match a predicate.
* This type is used by {@link CompositeMap}. * This type is used by {@link CompositeMap}.
*
* @author Arjen Poutsma * @author Arjen Poutsma
* @since 6.2 * @since 6.2
* @param <K> the type of keys maintained by this map * @param <K> the type of keys maintained by this map
@ -41,11 +42,11 @@ final class FilteredMap<K, V> extends AbstractMap<K, V> {
public FilteredMap(Map<K, V> delegate, Predicate<K> filter) { public FilteredMap(Map<K, V> delegate, Predicate<K> filter) {
Assert.notNull(delegate, "Delegate must not be null"); Assert.notNull(delegate, "Delegate must not be null");
Assert.notNull(filter, "Filter must not be null"); Assert.notNull(filter, "Filter must not be null");
this.delegate = delegate; this.delegate = delegate;
this.filter = filter; this.filter = filter;
} }
@Override @Override
public Set<Entry<K, V>> entrySet() { public Set<Entry<K, V>> entrySet() {
return new FilteredSet<>(this.delegate.entrySet(), entry -> this.filter.test(entry.getKey())); return new FilteredSet<>(this.delegate.entrySet(), entry -> this.filter.test(entry.getKey()));

22
spring-core/src/main/java/org/springframework/util/FilteredSet.java

@ -19,9 +19,12 @@ package org.springframework.util;
import java.util.Set; import java.util.Set;
import java.util.function.Predicate; import java.util.function.Predicate;
import org.springframework.lang.Nullable;
/** /**
* Set that filters out values that do not match a predicate. * Set that filters out values that do not match a predicate.
* This type is used by {@link CompositeMap}. * This type is used by {@link CompositeMap}.
*
* @author Arjen Poutsma * @author Arjen Poutsma
* @since 6.2 * @since 6.2
* @param <E> the type of elements maintained by this set * @param <E> the type of elements maintained by this set
@ -32,25 +35,21 @@ final class FilteredSet<E> extends FilteredCollection<E> implements Set<E> {
super(delegate, filter); super(delegate, filter);
} }
@Override @Override
public boolean equals(Object obj) { public boolean equals(@Nullable Object other) {
if (obj == this) { if (this == other) {
return true; return true;
} }
else if (obj instanceof Set<?> set) { if (other instanceof Set<?> otherSet && size() == otherSet.size()) {
if (set.size() != size()) {
return false;
}
try { try {
return containsAll(set); return containsAll(otherSet);
} }
catch (ClassCastException | NullPointerException ignored) { catch (ClassCastException | NullPointerException ignored) {
return false; // fall through
} }
} }
else { return false;
return false;
}
} }
@Override @Override
@ -63,4 +62,5 @@ final class FilteredSet<E> extends FilteredCollection<E> implements Set<E> {
} }
return hashCode; return hashCode;
} }
} }

67
spring-core/src/main/java/org/springframework/util/MultiToSingleValueMapAdapter.java

@ -62,6 +62,7 @@ final class MultiToSingleValueMapAdapter<K, V> implements Map<K, V>, Serializabl
this.targetMap = targetMap; this.targetMap = targetMap;
} }
@Override @Override
public int size() { public int size() {
return this.targetMap.size(); return this.targetMap.size();
@ -166,8 +167,6 @@ final class MultiToSingleValueMapAdapter<K, V> implements Map<K, V>, Serializabl
return values; return values;
} }
@Override @Override
public Set<Entry<K, V>> entrySet() { public Set<Entry<K, V>> entrySet() {
Set<Entry<K, V>> entries = this.entries; Set<Entry<K, V>> entries = this.entries;
@ -206,39 +205,55 @@ final class MultiToSingleValueMapAdapter<K, V> implements Map<K, V>, Serializabl
this.targetMap.forEach((k, vs) -> action.accept(k, vs.get(0))); this.targetMap.forEach((k, vs) -> action.accept(k, vs.get(0)));
} }
@Nullable
private V adaptValue(@Nullable List<V> values) {
if (!CollectionUtils.isEmpty(values)) {
return values.get(0);
}
else {
return null;
}
}
@Nullable
private List<V> adaptValue(@Nullable V value) {
if (value != null) {
return Collections.singletonList(value);
}
else {
return null;
}
}
@Override @Override
public boolean equals(@Nullable Object o) { public boolean equals(@Nullable Object other) {
if (o == this) { if (this == other) {
return true; return true;
} }
else if (o instanceof Map<?,?> other) { if (other instanceof Map<?,?> otherMap && size() == otherMap.size()) {
if (this.size() != other.size()) {
return false;
}
try { try {
for (Entry<K, V> e : entrySet()) { for (Entry<K, V> e : entrySet()) {
K key = e.getKey(); K key = e.getKey();
V value = e.getValue(); V value = e.getValue();
if (value == null) { if (value == null) {
if (other.get(key) != null || !other.containsKey(key)) { if (otherMap.get(key) != null || !otherMap.containsKey(key)) {
return false; return false;
} }
} }
else { else {
if (!value.equals(other.get(key))) { if (!value.equals(otherMap.get(key))) {
return false; return false;
} }
} }
} }
return true;
} }
catch (ClassCastException | NullPointerException ignore) { catch (ClassCastException | NullPointerException ignored) {
return false; // fall through
} }
return true;
}
else {
return false;
} }
return false;
} }
@Override @Override
@ -251,24 +266,4 @@ final class MultiToSingleValueMapAdapter<K, V> implements Map<K, V>, Serializabl
return this.targetMap.toString(); return this.targetMap.toString();
} }
@Nullable
private V adaptValue(@Nullable List<V> values) {
if (!CollectionUtils.isEmpty(values)) {
return values.get(0);
}
else {
return null;
}
}
@Nullable
private List<V> adaptValue(@Nullable V value) {
if (value != null) {
return Collections.singletonList(value);
}
else {
return null;
}
}
} }

11
spring-core/src/main/java/org/springframework/util/MultiValueMap.java

@ -97,8 +97,9 @@ public interface MultiValueMap<K, V> extends Map<K, List<V>> {
Map<K, V> toSingleValueMap(); Map<K, V> toSingleValueMap();
/** /**
* Return this map as a {@code Map} with the first values contained in this {@code MultiValueMap}. * Return this map as a {@code Map} with the first values contained in this
* The difference between this method and {@link #toSingleValueMap()} is * {@code MultiValueMap}.
* <p>The difference between this method and {@link #toSingleValueMap()} is
* that this method returns a view of the entries of this map, whereas * that this method returns a view of the entries of this map, whereas
* the latter returns a copy. * the latter returns a copy.
* @return a single value representation of this map * @return a single value representation of this map
@ -112,9 +113,9 @@ public interface MultiValueMap<K, V> extends Map<K, List<V>> {
/** /**
* Return a {@code MultiValueMap<K, V>} that adapts the given single-value * Return a {@code MultiValueMap<K, V>} that adapts the given single-value
* {@code Map<K, V>}. * {@code Map<K, V>}.
* The returned map cannot map multiple values to the same key, and doing so * <p>The returned map cannot map multiple values to the same key,
* results in an {@link UnsupportedOperationException}. Use * and doing so results in an {@link UnsupportedOperationException}.
* {@link #fromMultiValue(Map)} to support multiple values. * Use {@link #fromMultiValue(Map)} to support multiple values.
* @param map the map to be adapted * @param map the map to be adapted
* @param <K> the key type * @param <K> the key type
* @param <V> the value element type * @param <V> the value element type

10
spring-core/src/main/java/org/springframework/util/PlaceholderParser.java

@ -293,6 +293,7 @@ final class PlaceholderParser {
return (this.escape != null && index > 0 && value.charAt(index - 1) == this.escape); return (this.escape != null && index > 0 && value.charAt(index - 1) == this.escape);
} }
/** /**
* Provide the necessary context to handle and resolve underlying placeholders. * Provide the necessary context to handle and resolve underlying placeholders.
*/ */
@ -397,9 +398,9 @@ final class PlaceholderParser {
} }
return sb.toString(); return sb.toString();
} }
} }
/** /**
* A representation of the parsing of an input string. * A representation of the parsing of an input string.
* @param text the raw input string * @param text the raw input string
@ -415,9 +416,9 @@ final class PlaceholderParser {
throw ex.withValue(this.text); throw ex.withValue(this.text);
} }
} }
} }
/** /**
* A {@link Part} implementation that does not contain a valid placeholder. * A {@link Part} implementation that does not contain a valid placeholder.
* @param text the raw (and resolved) text * @param text the raw (and resolved) text
@ -428,9 +429,9 @@ final class PlaceholderParser {
public String resolve(PartResolutionContext resolutionContext) { public String resolve(PartResolutionContext resolutionContext) {
return this.text; return this.text;
} }
} }
/** /**
* A {@link Part} implementation that represents a single placeholder with * A {@link Part} implementation that represents a single placeholder with
* a hard-coded fallback. * a hard-coded fallback.
@ -479,9 +480,9 @@ final class PlaceholderParser {
parts.forEach(part -> sb.append(part.text())); parts.forEach(part -> sb.append(part.text()));
return sb.toString(); return sb.toString();
} }
} }
/** /**
* A {@link Part} implementation that represents a single placeholder * A {@link Part} implementation that represents a single placeholder
* containing nested placeholders. * containing nested placeholders.
@ -503,7 +504,6 @@ final class PlaceholderParser {
} }
return resolutionContext.handleUnresolvablePlaceholder(resolvedKey, this.text); return resolutionContext.handleUnresolvablePlaceholder(resolvedKey, this.text);
} }
} }
} }

2
spring-core/src/main/java/org/springframework/util/PlaceholderResolutionException.java

@ -39,6 +39,7 @@ public class PlaceholderResolutionException extends IllegalArgumentException {
private final List<String> values; private final List<String> values;
/** /**
* Create an exception using the specified reason for its message. * Create an exception using the specified reason for its message.
* @param reason the reason for the exception, should contain the placeholder * @param reason the reason for the exception, should contain the placeholder
@ -67,6 +68,7 @@ public class PlaceholderResolutionException extends IllegalArgumentException {
return sb.toString(); return sb.toString();
} }
/** /**
* Return a {@link PlaceholderResolutionException} that provides * Return a {@link PlaceholderResolutionException} that provides
* an additional parent value. * an additional parent value.

24
spring-core/src/main/java/org/springframework/util/SingleToMultiValueMapAdapter.java

@ -271,39 +271,35 @@ final class SingleToMultiValueMapAdapter<K, V> implements MultiValueMap<K, V>, S
this.targetMap.forEach((k, v) -> action.accept(k, Collections.singletonList(v))); this.targetMap.forEach((k, v) -> action.accept(k, Collections.singletonList(v)));
} }
@Override @Override
public boolean equals(@Nullable Object o) { public boolean equals(@Nullable Object other) {
if (o == this) { if (this == other) {
return true; return true;
} }
else if (o instanceof Map<?,?> other) { if (other instanceof Map<?,?> otherMap && size() == otherMap.size()) {
if (this.size() != other.size()) {
return false;
}
try { try {
for (Entry<K, List<V>> e : entrySet()) { for (Entry<K, List<V>> e : entrySet()) {
K key = e.getKey(); K key = e.getKey();
List<V> values = e.getValue(); List<V> values = e.getValue();
if (values == null) { if (values == null) {
if (other.get(key) != null || !other.containsKey(key)) { if (otherMap.get(key) != null || !otherMap.containsKey(key)) {
return false; return false;
} }
} }
else { else {
if (!values .equals(other.get(key))) { if (!values.equals(otherMap.get(key))) {
return false; return false;
} }
} }
} }
return true;
} }
catch (ClassCastException | NullPointerException ignore) { catch (ClassCastException | NullPointerException ignored) {
return false; // fall through
} }
return true;
}
else {
return false;
} }
return false;
} }
@Override @Override

11
spring-core/src/main/java/org/springframework/util/unit/DataSize.java

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2023 the original author or authors. * Copyright 2002-2024 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.
@ -247,14 +247,14 @@ public final class DataSize implements Comparable<DataSize>, Serializable {
@Override @Override
public boolean equals(@Nullable Object obj) { public boolean equals(@Nullable Object other) {
if (this == obj) { if (this == other) {
return true; return true;
} }
if (obj == null || getClass() != obj.getClass()) { if (other == null || getClass() != other.getClass()) {
return false; return false;
} }
DataSize that = (DataSize) obj; DataSize that = (DataSize) other;
return (this.bytes == that.bytes); return (this.bytes == that.bytes);
} }
@ -279,7 +279,6 @@ public final class DataSize implements Comparable<DataSize>, Serializable {
DataUnit defaultUnitToUse = (defaultUnit != null ? defaultUnit : DataUnit.BYTES); DataUnit defaultUnitToUse = (defaultUnit != null ? defaultUnit : DataUnit.BYTES);
return (StringUtils.hasLength(suffix) ? DataUnit.fromSuffix(suffix) : defaultUnitToUse); return (StringUtils.hasLength(suffix) ? DataUnit.fromSuffix(suffix) : defaultUnitToUse);
} }
} }
} }

20
spring-core/src/test/java/org/springframework/aot/hint/annotation/RegisterReflectionReflectiveProcessorTests.java

@ -38,6 +38,7 @@ import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
* Tests for {@link RegisterReflectionReflectiveProcessor}. * Tests for {@link RegisterReflectionReflectiveProcessor}.
* *
* @author Stephane Nicoll * @author Stephane Nicoll
* @since 6.2
*/ */
class RegisterReflectionReflectiveProcessorTests { class RegisterReflectionReflectiveProcessorTests {
@ -47,6 +48,7 @@ class RegisterReflectionReflectiveProcessorTests {
private final RuntimeHints hints = new RuntimeHints(); private final RuntimeHints hints = new RuntimeHints();
@Nested @Nested
class AnnotatedTypeTests { class AnnotatedTypeTests {
@ -73,6 +75,7 @@ class RegisterReflectionReflectiveProcessorTests {
} }
} }
@Nested @Nested
class AnnotatedMethodTests { class AnnotatedMethodTests {
@ -88,11 +91,12 @@ class RegisterReflectionReflectiveProcessorTests {
Method method = RegistrationMethodWithoutTarget.class.getDeclaredMethod("doReflection"); Method method = RegistrationMethodWithoutTarget.class.getDeclaredMethod("doReflection");
assertThatIllegalStateException() assertThatIllegalStateException()
.isThrownBy(() -> registerReflectionHints(method)) .isThrownBy(() -> registerReflectionHints(method))
.withMessageContaining("At least one class must be specified, could not detect target from '") .withMessageContaining("At least one class must be specified")
.withMessageContaining(method.toString()); .withMessageContaining(method.toString());
} }
} }
private void assertBasicTypeHint(Class<?> type, List<String> methodNames, List<MemberCategory> memberCategories) { private void assertBasicTypeHint(Class<?> type, List<String> methodNames, List<MemberCategory> memberCategories) {
TypeHint typeHint = getTypeHint(type); TypeHint typeHint = getTypeHint(type);
assertThat(typeHint.methods()).map(ExecutableHint::getName).hasSameElementsAs(methodNames); assertThat(typeHint.methods()).map(ExecutableHint::getName).hasSameElementsAs(methodNames);
@ -120,31 +124,32 @@ class RegisterReflectionReflectiveProcessorTests {
this.processor.registerReflectionHints(this.hints.reflection(), annotatedElement); this.processor.registerReflectionHints(this.hints.reflection(), annotatedElement);
} }
@RegisterReflection(classes = SimplePojo.class, memberCategories = MemberCategory.INVOKE_PUBLIC_METHODS) @RegisterReflection(classes = SimplePojo.class, memberCategories = MemberCategory.INVOKE_PUBLIC_METHODS)
static class RegistrationSimple {} static class RegistrationSimple {
}
@RegisterReflection(classes = { Number.class, Double.class }, @RegisterReflection(classes = { Number.class, Double.class },
classNames = { "java.lang.Integer", "java.lang.Float" }, memberCategories = MemberCategory.INVOKE_PUBLIC_METHODS) classNames = { "java.lang.Integer", "java.lang.Float" }, memberCategories = MemberCategory.INVOKE_PUBLIC_METHODS)
static class RegistrationMultipleTargets { static class RegistrationMultipleTargets {
} }
static class RegistrationMethod { static class RegistrationMethod {
@RegisterReflection(classes = SimplePojo.class, memberCategories = MemberCategory.INVOKE_DECLARED_METHODS) @RegisterReflection(classes = SimplePojo.class, memberCategories = MemberCategory.INVOKE_DECLARED_METHODS)
private void doReflection() { private void doReflection() {
} }
} }
static class RegistrationMethodWithoutTarget { static class RegistrationMethodWithoutTarget {
@RegisterReflection(memberCategories = MemberCategory.INVOKE_DECLARED_CONSTRUCTORS) @RegisterReflection(memberCategories = MemberCategory.INVOKE_DECLARED_CONSTRUCTORS)
private void doReflection() { private void doReflection() {
} }
} }
@ -171,6 +176,7 @@ class RegisterReflectionReflectiveProcessorTests {
} }
} }
@RegisterReflection(memberCategories = MemberCategory.INVOKE_DECLARED_CONSTRUCTORS) @RegisterReflection(memberCategories = MemberCategory.INVOKE_DECLARED_CONSTRUCTORS)
static class AnnotatedSimplePojo { static class AnnotatedSimplePojo {
@ -179,8 +185,6 @@ class RegisterReflectionReflectiveProcessorTests {
AnnotatedSimplePojo(String test) { AnnotatedSimplePojo(String test) {
this.test = test; this.test = test;
} }
} }
} }

Loading…
Cancel
Save