Merge branch 'framework-6.2'

Closes gh-41177
This commit is contained in:
Andy Wilkinson 2024-06-20 20:18:13 +01:00
commit 6d9977087a
10 changed files with 25 additions and 102 deletions

View File

@ -14,7 +14,7 @@ junitJupiterVersion=5.10.2
kotlinVersion=1.9.24
mavenVersion=3.9.4
nativeBuildToolsVersion=0.10.2
springFrameworkVersion=6.1.10
springFrameworkVersion=6.2.0-M4
springFramework60xVersion=6.0.21
tomcatVersion=10.1.25
snakeYamlVersion=2.2

View File

@ -1,5 +1,5 @@
/*
* Copyright 2012-2023 the original author or authors.
* Copyright 2012-2024 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.
@ -16,7 +16,6 @@
package org.springframework.boot.actuate.scheduling;
import java.lang.reflect.Method;
import java.time.Duration;
import java.util.Collection;
import java.util.Collections;
@ -46,7 +45,6 @@ import org.springframework.scheduling.config.Task;
import org.springframework.scheduling.config.TriggerTask;
import org.springframework.scheduling.support.CronTrigger;
import org.springframework.scheduling.support.PeriodicTrigger;
import org.springframework.scheduling.support.ScheduledMethodRunnable;
/**
* {@link Endpoint @Endpoint} to expose information about an application's scheduled
@ -284,13 +282,7 @@ public class ScheduledTasksEndpoint {
private final String target;
private RunnableDescriptor(Runnable runnable) {
if (runnable instanceof ScheduledMethodRunnable scheduledMethodRunnable) {
Method method = scheduledMethodRunnable.getMethod();
this.target = method.getDeclaringClass().getName() + "." + method.getName();
}
else {
this.target = runnable.getClass().getName();
}
this.target = runnable.toString();
}
public String getTarget() {

View File

@ -80,7 +80,7 @@ class ScheduledTasksEndpointTests {
assertThat(tasks.getCron()).hasSize(1);
CronTaskDescriptor description = (CronTaskDescriptor) tasks.getCron().get(0);
assertThat(description.getExpression()).isEqualTo("0 0 0/6 1/1 * ?");
assertThat(description.getRunnable().getTarget()).isEqualTo(CronTriggerRunnable.class.getName());
assertThat(description.getRunnable().getTarget()).contains(CronTriggerRunnable.class.getName());
});
}
@ -109,7 +109,7 @@ class ScheduledTasksEndpointTests {
FixedDelayTaskDescriptor description = (FixedDelayTaskDescriptor) tasks.getFixedDelay().get(0);
assertThat(description.getInitialDelay()).isEqualTo(2000);
assertThat(description.getInterval()).isEqualTo(1000);
assertThat(description.getRunnable().getTarget()).isEqualTo(FixedDelayTriggerRunnable.class.getName());
assertThat(description.getRunnable().getTarget()).contains(FixedDelayTriggerRunnable.class.getName());
});
}
@ -123,7 +123,7 @@ class ScheduledTasksEndpointTests {
FixedDelayTaskDescriptor description = (FixedDelayTaskDescriptor) tasks.getFixedDelay().get(0);
assertThat(description.getInitialDelay()).isEqualTo(0);
assertThat(description.getInterval()).isEqualTo(1000);
assertThat(description.getRunnable().getTarget()).isEqualTo(FixedDelayTriggerRunnable.class.getName());
assertThat(description.getRunnable().getTarget()).contains(FixedDelayTriggerRunnable.class.getName());
});
}
@ -152,7 +152,7 @@ class ScheduledTasksEndpointTests {
FixedRateTaskDescriptor description = (FixedRateTaskDescriptor) tasks.getFixedRate().get(0);
assertThat(description.getInitialDelay()).isEqualTo(3000);
assertThat(description.getInterval()).isEqualTo(2000);
assertThat(description.getRunnable().getTarget()).isEqualTo(FixedRateTriggerRunnable.class.getName());
assertThat(description.getRunnable().getTarget()).contains(FixedRateTriggerRunnable.class.getName());
});
}
@ -166,7 +166,7 @@ class ScheduledTasksEndpointTests {
FixedRateTaskDescriptor description = (FixedRateTaskDescriptor) tasks.getFixedRate().get(0);
assertThat(description.getInitialDelay()).isEqualTo(0);
assertThat(description.getInterval()).isEqualTo(2000);
assertThat(description.getRunnable().getTarget()).isEqualTo(FixedRateTriggerRunnable.class.getName());
assertThat(description.getRunnable().getTarget()).contains(FixedRateTriggerRunnable.class.getName());
});
}
@ -178,7 +178,7 @@ class ScheduledTasksEndpointTests {
assertThat(tasks.getFixedRate()).isEmpty();
assertThat(tasks.getCustom()).hasSize(1);
CustomTriggerTaskDescriptor description = (CustomTriggerTaskDescriptor) tasks.getCustom().get(0);
assertThat(description.getRunnable().getTarget()).isEqualTo(CustomTriggerRunnable.class.getName());
assertThat(description.getRunnable().getTarget()).contains(CustomTriggerRunnable.class.getName());
assertThat(description.getTrigger()).isEqualTo(CustomTriggerTask.trigger.toString());
});
}

View File

@ -157,6 +157,7 @@ public class DataSourceAutoConfiguration {
return StringUtils.hasText(environment.getProperty(DATASOURCE_URL_PROPERTY));
}
catch (IllegalArgumentException ex) {
// NOTE: This should be PlaceholderResolutionException
// Ignore unresolvable placeholder errors
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2012-2023 the original author or authors.
* Copyright 2012-2024 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.
@ -146,7 +146,7 @@ class HttpMessageConvertersTests {
}
assertThat(converterClasses).containsExactly(ByteArrayHttpMessageConverter.class,
StringHttpMessageConverter.class, ResourceHttpMessageConverter.class,
MappingJackson2HttpMessageConverter.class);
MappingJackson2HttpMessageConverter.class, MappingJackson2CborHttpMessageConverter.class);
}
private List<HttpMessageConverter<?>> extractFormPartConverters(List<HttpMessageConverter<?>> converters) {

View File

@ -16,27 +16,18 @@
package org.springframework.boot.test.mock.mockito;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.util.LinkedHashSet;
import java.util.Set;
import java.util.function.BiConsumer;
import org.mockito.Captor;
import org.mockito.MockitoAnnotations;
import org.springframework.test.context.TestContext;
import org.springframework.test.context.TestExecutionListener;
import org.springframework.test.context.support.AbstractTestExecutionListener;
import org.springframework.test.context.support.DependencyInjectionTestExecutionListener;
import org.springframework.util.ReflectionUtils;
import org.springframework.util.ReflectionUtils.FieldCallback;
/**
* {@link TestExecutionListener} to enable {@link MockBean @MockBean} and
* {@link SpyBean @SpyBean} support. Also triggers
* {@link MockitoAnnotations#openMocks(Object)} when any Mockito annotations used,
* primarily to allow {@link Captor @Captor} annotations.
* {@link SpyBean @SpyBean} support.
* <p>
* To use the automatic reset support of {@code @MockBean} and {@code @SpyBean}, configure
* {@link ResetMocksTestExecutionListener} as well.
@ -49,8 +40,6 @@ import org.springframework.util.ReflectionUtils.FieldCallback;
*/
public class MockitoTestExecutionListener extends AbstractTestExecutionListener {
private static final String MOCKS_ATTRIBUTE_NAME = MockitoTestExecutionListener.class.getName() + ".mocks";
@Override
public final int getOrder() {
return 1950;
@ -58,8 +47,6 @@ public class MockitoTestExecutionListener extends AbstractTestExecutionListener
@Override
public void prepareTestInstance(TestContext testContext) throws Exception {
closeMocks(testContext);
initMocks(testContext);
injectFields(testContext);
}
@ -67,41 +54,10 @@ public class MockitoTestExecutionListener extends AbstractTestExecutionListener
public void beforeTestMethod(TestContext testContext) throws Exception {
if (Boolean.TRUE.equals(
testContext.getAttribute(DependencyInjectionTestExecutionListener.REINJECT_DEPENDENCIES_ATTRIBUTE))) {
closeMocks(testContext);
initMocks(testContext);
reinjectFields(testContext);
}
}
@Override
public void afterTestMethod(TestContext testContext) throws Exception {
closeMocks(testContext);
}
@Override
public void afterTestClass(TestContext testContext) throws Exception {
closeMocks(testContext);
}
private void initMocks(TestContext testContext) {
if (hasMockitoAnnotations(testContext)) {
testContext.setAttribute(MOCKS_ATTRIBUTE_NAME, MockitoAnnotations.openMocks(testContext.getTestInstance()));
}
}
private void closeMocks(TestContext testContext) throws Exception {
Object mocks = testContext.getAttribute(MOCKS_ATTRIBUTE_NAME);
if (mocks instanceof AutoCloseable closeable) {
closeable.close();
}
}
private boolean hasMockitoAnnotations(TestContext testContext) {
MockitoAnnotationCollection collector = new MockitoAnnotationCollection();
ReflectionUtils.doWithFields(testContext.getTestClass(), collector);
return collector.hasAnnotations();
}
private void injectFields(TestContext testContext) {
postProcessFields(testContext, (mockitoField, postProcessor) -> postProcessor.inject(mockitoField.field,
mockitoField.target, mockitoField.definition));
@ -130,28 +86,6 @@ public class MockitoTestExecutionListener extends AbstractTestExecutionListener
}
}
/**
* {@link FieldCallback} to collect Mockito annotations.
*/
private static final class MockitoAnnotationCollection implements FieldCallback {
private final Set<Annotation> annotations = new LinkedHashSet<>();
@Override
public void doWith(Field field) throws IllegalArgumentException {
for (Annotation annotation : field.getDeclaredAnnotations()) {
if (annotation.annotationType().getName().startsWith("org.mockito")) {
this.annotations.add(annotation);
}
}
}
boolean hasAnnotations() {
return !this.annotations.isEmpty();
}
}
private static final class MockitoField {
private final Field field;

View File

@ -1,5 +1,5 @@
/*
* Copyright 2012-2023 the original author or authors.
* Copyright 2012-2024 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.
@ -53,14 +53,6 @@ class MockitoTestExecutionListenerTests {
@Mock
private MockitoPostProcessor postProcessor;
@Test
void prepareTestInstanceShouldInitMockitoAnnotations() throws Exception {
WithMockitoAnnotations instance = new WithMockitoAnnotations();
this.listener.prepareTestInstance(mockTestContext(instance));
assertThat(instance.mock).isNotNull();
assertThat(instance.captor).isNotNull();
}
@Test
void prepareTestInstanceShouldInjectMockBean() throws Exception {
given(this.applicationContext.getBean(MockitoPostProcessor.class)).willReturn(this.postProcessor);

View File

@ -27,9 +27,10 @@ import org.springframework.core.env.MapPropertySource;
import org.springframework.core.env.MutablePropertySources;
import org.springframework.mock.env.MockEnvironment;
import org.springframework.test.context.support.TestPropertySourceUtils;
import org.springframework.util.PlaceholderResolutionException;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
/**
* Tests for {@link SpringBootTestRandomPortEnvironmentPostProcessor}.
@ -169,7 +170,7 @@ class SpringBootTestRandomPortEnvironmentPostProcessorTests {
addTestPropertySource("0", null);
this.propertySources
.addLast(new MapPropertySource("other", Collections.singletonMap("management.server.port", "${port}")));
assertThatIllegalArgumentException()
assertThatExceptionOfType(PlaceholderResolutionException.class)
.isThrownBy(() -> this.postProcessor.postProcessEnvironment(this.environment, null))
.withMessage("Could not resolve placeholder 'port' in value \"${port}\"");
}
@ -196,7 +197,7 @@ class SpringBootTestRandomPortEnvironmentPostProcessorTests {
source.put("server.port", "${port}");
source.put("management.server.port", "9090");
this.propertySources.addLast(new MapPropertySource("other", source));
assertThatIllegalArgumentException()
assertThatExceptionOfType(PlaceholderResolutionException.class)
.isThrownBy(() -> this.postProcessor.postProcessEnvironment(this.environment, null))
.withMessage("Could not resolve placeholder 'port' in value \"${port}\"");
}

View File

@ -56,7 +56,8 @@ class ConfigDataEnvironmentContributorPlaceholdersResolver implements Placeholde
this.failOnResolveFromInactiveContributor = failOnResolveFromInactiveContributor;
this.conversionService = conversionService;
this.helper = new PropertyPlaceholderHelper(SystemPropertyUtils.PLACEHOLDER_PREFIX,
SystemPropertyUtils.PLACEHOLDER_SUFFIX, SystemPropertyUtils.VALUE_SEPARATOR, true);
SystemPropertyUtils.PLACEHOLDER_SUFFIX, SystemPropertyUtils.VALUE_SEPARATOR,
SystemPropertyUtils.ESCAPE_CHARACTER, true);
}
@Override

View File

@ -1,5 +1,5 @@
/*
* Copyright 2012-2022 the original author or authors.
* Copyright 2012-2024 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.
@ -47,8 +47,10 @@ public class PropertySourcesPlaceholdersResolver implements PlaceholdersResolver
public PropertySourcesPlaceholdersResolver(Iterable<PropertySource<?>> sources, PropertyPlaceholderHelper helper) {
this.sources = sources;
this.helper = (helper != null) ? helper : new PropertyPlaceholderHelper(SystemPropertyUtils.PLACEHOLDER_PREFIX,
SystemPropertyUtils.PLACEHOLDER_SUFFIX, SystemPropertyUtils.VALUE_SEPARATOR, true);
this.helper = (helper != null) ? helper
: new PropertyPlaceholderHelper(SystemPropertyUtils.PLACEHOLDER_PREFIX,
SystemPropertyUtils.PLACEHOLDER_SUFFIX, SystemPropertyUtils.VALUE_SEPARATOR,
SystemPropertyUtils.ESCAPE_CHARACTER, true);
}
@Override