Skip to content

Commit

Permalink
Merge branch '5.3.x'
Browse files Browse the repository at this point in the history
# Conflicts:
#	spring-core/spring-core.gradle
  • Loading branch information
jhoeller committed Sep 23, 2021
2 parents 66b15ef + e29cfa3 commit 0241c5e
Show file tree
Hide file tree
Showing 6 changed files with 123 additions and 30 deletions.
44 changes: 29 additions & 15 deletions spring-beans/src/main/java/org/springframework/beans/BeanUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -226,32 +226,46 @@ public static <T> T instantiateClass(Constructor<T> ctor, Object... args) throws
}

/**
* Return a resolvable constructor for the provided class, either a primary constructor
* or single public constructor or simply a default constructor. Callers have to be
* prepared to resolve arguments for the returned constructor's parameters, if any.
* Return a resolvable constructor for the provided class, either a primary or single
* public constructor with arguments, or a single non-public constructor with arguments,
* or simply a default constructor. Callers have to be prepared to resolve arguments
* for the returned constructor's parameters, if any.
* @param clazz the class to check
* @throws IllegalStateException in case of no unique constructor found at all
* @since 5.3
* @see #findPrimaryConstructor
*/
@SuppressWarnings("unchecked")
public static <T> Constructor<T> getResolvableConstructor(Class<T> clazz) {
Constructor<T> ctor = findPrimaryConstructor(clazz);
if (ctor == null) {
Constructor<?>[] ctors = clazz.getConstructors();
if (ctor != null) {
return ctor;
}

Constructor<?>[] ctors = clazz.getConstructors();
if (ctors.length == 1) {
// A single public constructor
return (Constructor<T>) ctors[0];
}
else if (ctors.length == 0){
ctors = clazz.getDeclaredConstructors();
if (ctors.length == 1) {
ctor = (Constructor<T>) ctors[0];
// A single non-public constructor, e.g. from a non-public record type
return (Constructor<T>) ctors[0];
}
else {
try {
ctor = clazz.getDeclaredConstructor();
}
catch (NoSuchMethodException ex) {
throw new IllegalStateException("No primary or single public constructor found for " +
clazz + " - and no default constructor found either");
}
}
else {
// Several public constructors -> let's take the default constructor
try {
return clazz.getDeclaredConstructor();
}
catch (NoSuchMethodException ex) {
// Giving up...
}
}
return ctor;

// No unique constructor at all
throw new IllegalStateException("No primary or single unique constructor found for " + clazz);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@
import java.lang.reflect.Executable;
import java.lang.reflect.Member;
import java.lang.reflect.Method;
import java.util.HashSet;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.Set;
import java.util.function.Supplier;

Expand Down Expand Up @@ -422,54 +423,108 @@ public Method getResolvedFactoryMethod() {
return this.factoryMethodToIntrospect;
}

/**
* Register an externally managed configuration method or field.
*/
public void registerExternallyManagedConfigMember(Member configMember) {
synchronized (this.postProcessingLock) {
if (this.externallyManagedConfigMembers == null) {
this.externallyManagedConfigMembers = new HashSet<>(1);
this.externallyManagedConfigMembers = new LinkedHashSet<>(1);
}
this.externallyManagedConfigMembers.add(configMember);
}
}

/**
* Check whether the given method or field is an externally managed configuration member.
*/
public boolean isExternallyManagedConfigMember(Member configMember) {
synchronized (this.postProcessingLock) {
return (this.externallyManagedConfigMembers != null &&
this.externallyManagedConfigMembers.contains(configMember));
}
}

/**
* Return all externally managed configuration methods and fields (as an immutable Set).
* @since 5.3.11
*/
public Set<Member> getExternallyManagedConfigMembers() {
synchronized (this.postProcessingLock) {
return (this.externallyManagedConfigMembers != null ?
Collections.unmodifiableSet(new LinkedHashSet<>(this.externallyManagedConfigMembers)) :
Collections.emptySet());
}
}

/**
* Register an externally managed configuration initialization method.
*/
public void registerExternallyManagedInitMethod(String initMethod) {
synchronized (this.postProcessingLock) {
if (this.externallyManagedInitMethods == null) {
this.externallyManagedInitMethods = new HashSet<>(1);
this.externallyManagedInitMethods = new LinkedHashSet<>(1);
}
this.externallyManagedInitMethods.add(initMethod);
}
}

/**
* Check whether the given method name indicates an externally managed initialization method.
*/
public boolean isExternallyManagedInitMethod(String initMethod) {
synchronized (this.postProcessingLock) {
return (this.externallyManagedInitMethods != null &&
this.externallyManagedInitMethods.contains(initMethod));
}
}

/**
* Return all externally managed initialization methods (as an immutable Set).
* @since 5.3.11
*/
public Set<String> getExternallyManagedInitMethods() {
synchronized (this.postProcessingLock) {
return (this.externallyManagedInitMethods != null ?
Collections.unmodifiableSet(new LinkedHashSet<>(this.externallyManagedInitMethods)) :
Collections.emptySet());
}
}

/**
* Register an externally managed configuration destruction method.
*/
public void registerExternallyManagedDestroyMethod(String destroyMethod) {
synchronized (this.postProcessingLock) {
if (this.externallyManagedDestroyMethods == null) {
this.externallyManagedDestroyMethods = new HashSet<>(1);
this.externallyManagedDestroyMethods = new LinkedHashSet<>(1);
}
this.externallyManagedDestroyMethods.add(destroyMethod);
}
}

/**
* Check whether the given method name indicates an externally managed destruction method.
*/
public boolean isExternallyManagedDestroyMethod(String destroyMethod) {
synchronized (this.postProcessingLock) {
return (this.externallyManagedDestroyMethods != null &&
this.externallyManagedDestroyMethods.contains(destroyMethod));
}
}

/**
* Return all externally managed destruction methods (as an immutable Set).
* @since 5.3.11
*/
public Set<String> getExternallyManagedDestroyMethods() {
synchronized (this.postProcessingLock) {
return (this.externallyManagedDestroyMethods != null ?
Collections.unmodifiableSet(new LinkedHashSet<>(this.externallyManagedDestroyMethods)) :
Collections.emptySet());
}
}


@Override
public RootBeanDefinition cloneBeanDefinition() {
Expand Down
10 changes: 5 additions & 5 deletions spring-core/spring-core.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -48,21 +48,21 @@ dependencies {
optional("io.reactivex.rxjava3:rxjava")
optional("io.smallrye.reactive:mutiny")
optional("io.netty:netty-buffer")
testImplementation("io.projectreactor:reactor-test")
testImplementation("com.google.code.findbugs:jsr305")
testImplementation("jakarta.annotation:jakarta.annotation-api")
testImplementation("jakarta.xml.bind:jakarta.xml.bind-api")
testImplementation("com.google.code.findbugs:jsr305")
testImplementation("com.fasterxml.woodstox:woodstox-core")
testImplementation("org.xmlunit:xmlunit-assertj")
testImplementation("org.xmlunit:xmlunit-matchers")
testImplementation("io.projectreactor:reactor-test")
testImplementation("io.projectreactor.tools:blockhound")
testFixturesImplementation("io.projectreactor:reactor-test")
testFixturesImplementation("com.google.code.findbugs:jsr305")
testFixturesImplementation("org.junit.platform:junit-platform-launcher")
testFixturesImplementation("org.junit.jupiter:junit-jupiter-api")
testFixturesImplementation("org.junit.jupiter:junit-jupiter-params")
testFixturesImplementation("org.assertj:assertj-core")
testFixturesImplementation("org.xmlunit:xmlunit-assertj")
testFixturesImplementation("io.projectreactor:reactor-test")
}

jar {
Expand Down Expand Up @@ -90,7 +90,7 @@ jar {
}

test {
// Make sure the classes dir is used on the test classpath (required by ResourceTests)
// When test fixtures are involved, the JAR is used by default
// Make sure the classes dir is used on the test classpath (required by ResourceTests).
// When test fixtures are involved, the JAR is used by default.
classpath = sourceSets.main.output.classesDirs + classpath - files(jar.archiveFile)
}
Original file line number Diff line number Diff line change
Expand Up @@ -858,7 +858,7 @@ public boolean contains(@Nullable Object o) {
Reference<K, V> ref = ConcurrentReferenceHashMap.this.getReference(entry.getKey(), Restructure.NEVER);
Entry<K, V> otherEntry = (ref != null ? ref.get() : null);
if (otherEntry != null) {
return ObjectUtils.nullSafeEquals(otherEntry.getValue(), otherEntry.getValue());
return ObjectUtils.nullSafeEquals(entry.getValue(), otherEntry.getValue());
}
}
return false;
Expand Down Expand Up @@ -966,6 +966,7 @@ private void moveToNextSegment() {
public void remove() {
Assert.state(this.last != null, "No element to remove");
ConcurrentReferenceHashMap.this.remove(this.last.getKey());
this.last = null;
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2020 the original author or authors.
* Copyright 2002-2021 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.
Expand Down Expand Up @@ -41,11 +41,13 @@

import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
import static org.assertj.core.api.Assertions.assertThatIllegalStateException;

/**
* Tests for {@link ConcurrentReferenceHashMap}.
*
* @author Phillip Webb
* @author Juergen Hoeller
*/
class ConcurrentReferenceHashMapTests {

Expand Down Expand Up @@ -466,6 +468,7 @@ void shouldRemoveViaEntrySet() {
iterator.next();
iterator.next();
iterator.remove();
assertThatIllegalStateException().isThrownBy(iterator::remove);
iterator.next();
assertThat(iterator.hasNext()).isFalse();
assertThat(this.map).hasSize(2);
Expand All @@ -486,6 +489,26 @@ void shouldSetViaEntrySet() {
assertThat(this.map.get(2)).isEqualTo("2b");
}

@Test
void containsViaEntrySet() {
this.map.put(1, "1");
this.map.put(2, "2");
this.map.put(3, "3");
Set<Map.Entry<Integer, String>> entrySet = this.map.entrySet();
Set<Map.Entry<Integer, String>> copy = new HashMap<>(this.map).entrySet();
copy.forEach(entry -> assertThat(entrySet.contains(entry)).isTrue());
this.map.put(1, "A");
this.map.put(2, "B");
this.map.put(3, "C");
copy.forEach(entry -> assertThat(entrySet.contains(entry)).isFalse());
this.map.put(1, "1");
this.map.put(2, "2");
this.map.put(3, "3");
copy.forEach(entry -> assertThat(entrySet.contains(entry)).isTrue());
entrySet.clear();
copy.forEach(entry -> assertThat(entrySet.contains(entry)).isFalse());
}

@Test
@Disabled("Intended for use during development only")
void shouldBeFasterThanSynchronizedMap() throws InterruptedException {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2020 the original author or authors.
* Copyright 2002-2021 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.
Expand Down Expand Up @@ -582,13 +582,13 @@ protected void doRescheduleTask(Object task) {
/**
* Log a task that has been rejected by {@link #doRescheduleTask}.
* <p>The default implementation simply logs a corresponding message
* at debug level.
* at warn level.
* @param task the rejected task object
* @param ex the exception thrown from {@link #doRescheduleTask}
*/
protected void logRejectedTask(Object task, RuntimeException ex) {
if (logger.isDebugEnabled()) {
logger.debug("Listener container task [" + task + "] has been rejected and paused: " + ex);
if (logger.isWarnEnabled()) {
logger.warn("Listener container task [" + task + "] has been rejected and paused: " + ex);
}
}

Expand Down

0 comments on commit 0241c5e

Please sign in to comment.