Nullability refinements and related polishing
See gh-32475
This commit is contained in:
parent
cd7ba1835c
commit
c531a8a705
|
@ -364,18 +364,18 @@ public abstract class AopUtils {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Inner class to avoid a hard dependency on Kotlin at runtime.
|
* Inner class to avoid a hard dependency on Kotlin at runtime.
|
||||||
*/
|
*/
|
||||||
private static class KotlinDelegate {
|
private static class KotlinDelegate {
|
||||||
|
|
||||||
public static Publisher<?> invokeSuspendingFunction(Method method, Object target, Object... args) {
|
public static Publisher<?> invokeSuspendingFunction(Method method, @Nullable Object target, Object... args) {
|
||||||
Continuation<?> continuation = (Continuation<?>) args[args.length -1];
|
Continuation<?> continuation = (Continuation<?>) args[args.length -1];
|
||||||
Assert.state(continuation != null, "No Continuation available");
|
Assert.state(continuation != null, "No Continuation available");
|
||||||
CoroutineContext context = continuation.getContext().minusKey(Job.Key);
|
CoroutineContext context = continuation.getContext().minusKey(Job.Key);
|
||||||
return CoroutinesUtils.invokeSuspendingFunction(context, method, target, args);
|
return CoroutinesUtils.invokeSuspendingFunction(context, method, target, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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.
|
||||||
|
@ -845,8 +845,10 @@ public abstract class AbstractNestablePropertyAccessor extends AbstractPropertyA
|
||||||
* @return the PropertyAccessor instance, either cached or newly created
|
* @return the PropertyAccessor instance, either cached or newly created
|
||||||
*/
|
*/
|
||||||
private AbstractNestablePropertyAccessor getNestedPropertyAccessor(String nestedProperty) {
|
private AbstractNestablePropertyAccessor getNestedPropertyAccessor(String nestedProperty) {
|
||||||
if (this.nestedPropertyAccessors == null) {
|
Map<String, AbstractNestablePropertyAccessor> nestedAccessors = this.nestedPropertyAccessors;
|
||||||
this.nestedPropertyAccessors = new HashMap<>();
|
if (nestedAccessors == null) {
|
||||||
|
nestedAccessors = new HashMap<>();
|
||||||
|
this.nestedPropertyAccessors = nestedAccessors;
|
||||||
}
|
}
|
||||||
// Get value of bean property.
|
// Get value of bean property.
|
||||||
PropertyTokenHolder tokens = getPropertyNameTokens(nestedProperty);
|
PropertyTokenHolder tokens = getPropertyNameTokens(nestedProperty);
|
||||||
|
@ -862,7 +864,7 @@ public abstract class AbstractNestablePropertyAccessor extends AbstractPropertyA
|
||||||
}
|
}
|
||||||
|
|
||||||
// Lookup cached sub-PropertyAccessor, create new one if not found.
|
// Lookup cached sub-PropertyAccessor, create new one if not found.
|
||||||
AbstractNestablePropertyAccessor nestedPa = this.nestedPropertyAccessors.get(canonicalName);
|
AbstractNestablePropertyAccessor nestedPa = nestedAccessors.get(canonicalName);
|
||||||
if (nestedPa == null || nestedPa.getWrappedInstance() != ObjectUtils.unwrapOptional(value)) {
|
if (nestedPa == null || nestedPa.getWrappedInstance() != ObjectUtils.unwrapOptional(value)) {
|
||||||
if (logger.isTraceEnabled()) {
|
if (logger.isTraceEnabled()) {
|
||||||
logger.trace("Creating new nested " + getClass().getSimpleName() + " for property '" + canonicalName + "'");
|
logger.trace("Creating new nested " + getClass().getSimpleName() + " for property '" + canonicalName + "'");
|
||||||
|
@ -871,7 +873,7 @@ public abstract class AbstractNestablePropertyAccessor extends AbstractPropertyA
|
||||||
// Inherit all type-specific PropertyEditors.
|
// Inherit all type-specific PropertyEditors.
|
||||||
copyDefaultEditorsTo(nestedPa);
|
copyDefaultEditorsTo(nestedPa);
|
||||||
copyCustomEditorsTo(nestedPa, canonicalName);
|
copyCustomEditorsTo(nestedPa, canonicalName);
|
||||||
this.nestedPropertyAccessors.put(canonicalName, nestedPa);
|
nestedAccessors.put(canonicalName, nestedPa);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (logger.isTraceEnabled()) {
|
if (logger.isTraceEnabled()) {
|
||||||
|
|
|
@ -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.
|
||||||
|
@ -54,6 +54,7 @@ import org.springframework.core.io.DescriptiveResource;
|
||||||
import org.springframework.core.io.Resource;
|
import org.springframework.core.io.Resource;
|
||||||
import org.springframework.core.io.support.EncodedResource;
|
import org.springframework.core.io.support.EncodedResource;
|
||||||
import org.springframework.lang.Nullable;
|
import org.springframework.lang.Nullable;
|
||||||
|
import org.springframework.util.Assert;
|
||||||
import org.springframework.util.ObjectUtils;
|
import org.springframework.util.ObjectUtils;
|
||||||
import org.springframework.util.StringUtils;
|
import org.springframework.util.StringUtils;
|
||||||
|
|
||||||
|
@ -250,6 +251,7 @@ public class GroovyBeanDefinitionReader extends AbstractBeanDefinitionReader imp
|
||||||
@SuppressWarnings("serial")
|
@SuppressWarnings("serial")
|
||||||
Closure<Object> beans = new Closure<>(this) {
|
Closure<Object> beans = new Closure<>(this) {
|
||||||
@Override
|
@Override
|
||||||
|
@Nullable
|
||||||
public Object call(Object... args) {
|
public Object call(Object... args) {
|
||||||
invokeBeanDefiningClosure((Closure<?>) args[0]);
|
invokeBeanDefiningClosure((Closure<?>) args[0]);
|
||||||
return null;
|
return null;
|
||||||
|
@ -425,6 +427,7 @@ public class GroovyBeanDefinitionReader extends AbstractBeanDefinitionReader imp
|
||||||
|
|
||||||
private boolean addDeferredProperty(String property, Object newValue) {
|
private boolean addDeferredProperty(String property, Object newValue) {
|
||||||
if (newValue instanceof List || newValue instanceof Map) {
|
if (newValue instanceof List || newValue instanceof Map) {
|
||||||
|
Assert.state(this.currentBeanDefinition != null, "No current bean definition set");
|
||||||
this.deferredProperties.put(this.currentBeanDefinition.getBeanName() + '.' + property,
|
this.deferredProperties.put(this.currentBeanDefinition.getBeanName() + '.' + property,
|
||||||
new DeferredProperty(this.currentBeanDefinition, property, newValue));
|
new DeferredProperty(this.currentBeanDefinition, property, newValue));
|
||||||
return true;
|
return true;
|
||||||
|
@ -640,6 +643,7 @@ public class GroovyBeanDefinitionReader extends AbstractBeanDefinitionReader imp
|
||||||
this.currentBeanDefinition = current;
|
this.currentBeanDefinition = current;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Assert.state(this.currentBeanDefinition != null, "No current bean definition set");
|
||||||
this.currentBeanDefinition.addProperty(name, value);
|
this.currentBeanDefinition.addProperty(name, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -654,6 +658,7 @@ public class GroovyBeanDefinitionReader extends AbstractBeanDefinitionReader imp
|
||||||
* </ul>
|
* </ul>
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
|
@Nullable
|
||||||
public Object getProperty(String name) {
|
public Object getProperty(String name) {
|
||||||
Binding binding = getBinding();
|
Binding binding = getBinding();
|
||||||
if (binding != null && binding.hasVariable(name)) {
|
if (binding != null && binding.hasVariable(name)) {
|
||||||
|
@ -727,9 +732,10 @@ public class GroovyBeanDefinitionReader extends AbstractBeanDefinitionReader imp
|
||||||
|
|
||||||
private final String name;
|
private final String name;
|
||||||
|
|
||||||
|
@Nullable
|
||||||
public Object value;
|
public Object value;
|
||||||
|
|
||||||
public DeferredProperty(GroovyBeanDefinitionWrapper beanDefinition, String name, Object value) {
|
public DeferredProperty(GroovyBeanDefinitionWrapper beanDefinition, String name, @Nullable Object value) {
|
||||||
this.beanDefinition = beanDefinition;
|
this.beanDefinition = beanDefinition;
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.value = value;
|
this.value = value;
|
||||||
|
@ -762,6 +768,7 @@ public class GroovyBeanDefinitionReader extends AbstractBeanDefinitionReader imp
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@Nullable
|
||||||
public Object getProperty(String property) {
|
public Object getProperty(String property) {
|
||||||
if (property.equals("beanName")) {
|
if (property.equals("beanName")) {
|
||||||
return getBeanName();
|
return getBeanName();
|
||||||
|
@ -769,13 +776,10 @@ public class GroovyBeanDefinitionReader extends AbstractBeanDefinitionReader imp
|
||||||
else if (property.equals("source")) {
|
else if (property.equals("source")) {
|
||||||
return getSource();
|
return getSource();
|
||||||
}
|
}
|
||||||
else if (this.beanDefinition != null) {
|
else {
|
||||||
return new GroovyPropertyValue(
|
return new GroovyPropertyValue(
|
||||||
property, this.beanDefinition.getBeanDefinition().getPropertyValues().get(property));
|
property, this.beanDefinition.getBeanDefinition().getPropertyValues().get(property));
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
return this.metaClass.getProperty(this, property);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -804,9 +808,10 @@ public class GroovyBeanDefinitionReader extends AbstractBeanDefinitionReader imp
|
||||||
|
|
||||||
private final String propertyName;
|
private final String propertyName;
|
||||||
|
|
||||||
|
@Nullable
|
||||||
private final Object propertyValue;
|
private final Object propertyValue;
|
||||||
|
|
||||||
public GroovyPropertyValue(String propertyName, Object propertyValue) {
|
public GroovyPropertyValue(String propertyName, @Nullable Object propertyValue) {
|
||||||
this.propertyName = propertyName;
|
this.propertyName = propertyName;
|
||||||
this.propertyValue = propertyValue;
|
this.propertyValue = propertyValue;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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.
|
||||||
|
@ -84,7 +84,7 @@ class GroovyBeanDefinitionWrapper extends GroovyObjectSupport {
|
||||||
this(beanName, clazz, null);
|
this(beanName, clazz, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
GroovyBeanDefinitionWrapper(@Nullable String beanName, Class<?> clazz, @Nullable Collection<?> constructorArgs) {
|
GroovyBeanDefinitionWrapper(@Nullable String beanName, @Nullable Class<?> clazz, @Nullable Collection<?> constructorArgs) {
|
||||||
this.beanName = beanName;
|
this.beanName = beanName;
|
||||||
this.clazz = clazz;
|
this.clazz = clazz;
|
||||||
this.constructorArgs = constructorArgs;
|
this.constructorArgs = constructorArgs;
|
||||||
|
@ -130,11 +130,12 @@ class GroovyBeanDefinitionWrapper extends GroovyObjectSupport {
|
||||||
}
|
}
|
||||||
|
|
||||||
BeanDefinitionHolder getBeanDefinitionHolder() {
|
BeanDefinitionHolder getBeanDefinitionHolder() {
|
||||||
return new BeanDefinitionHolder(getBeanDefinition(), getBeanName());
|
Assert.state(this.beanName != null, "Bean name must be set");
|
||||||
|
return new BeanDefinitionHolder(getBeanDefinition(), this.beanName);
|
||||||
}
|
}
|
||||||
|
|
||||||
void setParent(Object obj) {
|
void setParent(@Nullable Object obj) {
|
||||||
Assert.notNull(obj, "Parent bean cannot be set to a null runtime bean reference.");
|
Assert.notNull(obj, "Parent bean cannot be set to a null runtime bean reference");
|
||||||
if (obj instanceof String name) {
|
if (obj instanceof String name) {
|
||||||
this.parentName = name;
|
this.parentName = name;
|
||||||
}
|
}
|
||||||
|
@ -148,7 +149,7 @@ class GroovyBeanDefinitionWrapper extends GroovyObjectSupport {
|
||||||
getBeanDefinition().setAbstract(false);
|
getBeanDefinition().setAbstract(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
GroovyBeanDefinitionWrapper addProperty(String propertyName, Object propertyValue) {
|
GroovyBeanDefinitionWrapper addProperty(String propertyName, @Nullable Object propertyValue) {
|
||||||
if (propertyValue instanceof GroovyBeanDefinitionWrapper wrapper) {
|
if (propertyValue instanceof GroovyBeanDefinitionWrapper wrapper) {
|
||||||
propertyValue = wrapper.getBeanDefinition();
|
propertyValue = wrapper.getBeanDefinition();
|
||||||
}
|
}
|
||||||
|
@ -158,6 +159,7 @@ class GroovyBeanDefinitionWrapper extends GroovyObjectSupport {
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@Nullable
|
||||||
public Object getProperty(String property) {
|
public Object getProperty(String property) {
|
||||||
Assert.state(this.definitionWrapper != null, "BeanDefinition wrapper not initialized");
|
Assert.state(this.definitionWrapper != null, "BeanDefinition wrapper not initialized");
|
||||||
if (this.definitionWrapper.isReadableProperty(property)) {
|
if (this.definitionWrapper.isReadableProperty(property)) {
|
||||||
|
@ -170,7 +172,7 @@ class GroovyBeanDefinitionWrapper extends GroovyObjectSupport {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setProperty(String property, Object newValue) {
|
public void setProperty(String property, @Nullable Object newValue) {
|
||||||
if (PARENT.equals(property)) {
|
if (PARENT.equals(property)) {
|
||||||
setParent(newValue);
|
setParent(newValue);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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.
|
||||||
|
@ -638,7 +638,7 @@ public class RootBeanDefinition extends AbstractBeanDefinition {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean hasAnyExternallyManagedMethod(Set<String> candidates, String methodName) {
|
private static boolean hasAnyExternallyManagedMethod(@Nullable Set<String> candidates, String methodName) {
|
||||||
if (candidates != null) {
|
if (candidates != null) {
|
||||||
for (String candidate : candidates) {
|
for (String candidate : candidates) {
|
||||||
int indexOfDot = candidate.lastIndexOf('.');
|
int indexOfDot = candidate.lastIndexOf('.');
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2021 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.
|
||||||
|
@ -126,9 +126,10 @@ public class DefaultBeanDefinitionDocumentReader implements BeanDefinitionDocume
|
||||||
// then ultimately reset this.delegate back to its original (parent) reference.
|
// then ultimately reset this.delegate back to its original (parent) reference.
|
||||||
// this behavior emulates a stack of delegates without actually necessitating one.
|
// this behavior emulates a stack of delegates without actually necessitating one.
|
||||||
BeanDefinitionParserDelegate parent = this.delegate;
|
BeanDefinitionParserDelegate parent = this.delegate;
|
||||||
this.delegate = createDelegate(getReaderContext(), root, parent);
|
BeanDefinitionParserDelegate current = createDelegate(getReaderContext(), root, parent);
|
||||||
|
this.delegate = current;
|
||||||
|
|
||||||
if (this.delegate.isDefaultNamespace(root)) {
|
if (current.isDefaultNamespace(root)) {
|
||||||
String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);
|
String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);
|
||||||
if (StringUtils.hasText(profileSpec)) {
|
if (StringUtils.hasText(profileSpec)) {
|
||||||
String[] specifiedProfiles = StringUtils.tokenizeToStringArray(
|
String[] specifiedProfiles = StringUtils.tokenizeToStringArray(
|
||||||
|
@ -146,7 +147,7 @@ public class DefaultBeanDefinitionDocumentReader implements BeanDefinitionDocume
|
||||||
}
|
}
|
||||||
|
|
||||||
preProcessXml(root);
|
preProcessXml(root);
|
||||||
parseBeanDefinitions(root, this.delegate);
|
parseBeanDefinitions(root, current);
|
||||||
postProcessXml(root);
|
postProcessXml(root);
|
||||||
|
|
||||||
this.delegate = parent;
|
this.delegate = parent;
|
||||||
|
|
|
@ -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.
|
||||||
|
@ -1096,7 +1096,13 @@ public abstract class CacheAspectSupport extends AbstractCacheInvoker
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (KotlinDetector.isKotlinReflectPresent() && KotlinDetector.isSuspendingFunction(method)) {
|
if (KotlinDetector.isKotlinReflectPresent() && KotlinDetector.isSuspendingFunction(method)) {
|
||||||
return Mono.fromFuture(cache.retrieve(key, () -> ((Mono<?>) invokeOperation(invoker)).toFuture()));
|
return Mono.fromFuture(cache.retrieve(key, () -> {
|
||||||
|
Mono<?> mono = ((Mono<?>) invokeOperation(invoker));
|
||||||
|
if (mono == null) {
|
||||||
|
mono = Mono.empty();
|
||||||
|
}
|
||||||
|
return mono.toFuture();
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
return NOT_HANDLED;
|
return NOT_HANDLED;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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.
|
||||||
|
@ -78,12 +78,13 @@ public class CacheInterceptor extends CacheAspectSupport implements MethodInterc
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Inner class to avoid a hard dependency on Kotlin at runtime.
|
* Inner class to avoid a hard dependency on Kotlin at runtime.
|
||||||
*/
|
*/
|
||||||
private static class KotlinDelegate {
|
private static class KotlinDelegate {
|
||||||
|
|
||||||
public static Publisher<?> invokeSuspendingFunction(Method method, Object target, Object... args) {
|
public static Publisher<?> invokeSuspendingFunction(Method method, @Nullable Object target, Object... args) {
|
||||||
Continuation<?> continuation = (Continuation<?>) args[args.length - 1];
|
Continuation<?> continuation = (Continuation<?>) args[args.length - 1];
|
||||||
CoroutineContext coroutineContext = continuation.getContext().minusKey(Job.Key);
|
CoroutineContext coroutineContext = continuation.getContext().minusKey(Job.Key);
|
||||||
return CoroutinesUtils.invokeSuspendingFunction(coroutineContext, method, target, args);
|
return CoroutinesUtils.invokeSuspendingFunction(coroutineContext, method, target, args);
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2022 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.
|
||||||
|
@ -257,6 +257,7 @@ public abstract class AbstractAotProcessor<T> {
|
||||||
* @return this builder for method chaining
|
* @return this builder for method chaining
|
||||||
*/
|
*/
|
||||||
public Builder groupId(String groupId) {
|
public Builder groupId(String groupId) {
|
||||||
|
Assert.hasText(groupId, "'groupId' must not be empty");
|
||||||
this.groupId = groupId;
|
this.groupId = groupId;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
@ -268,6 +269,7 @@ public abstract class AbstractAotProcessor<T> {
|
||||||
* @return this builder for method chaining
|
* @return this builder for method chaining
|
||||||
*/
|
*/
|
||||||
public Builder artifactId(String artifactId) {
|
public Builder artifactId(String artifactId) {
|
||||||
|
Assert.hasText(artifactId, "'artifactId' must not be empty");
|
||||||
this.artifactId = artifactId;
|
this.artifactId = artifactId;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
@ -279,14 +281,12 @@ public abstract class AbstractAotProcessor<T> {
|
||||||
Assert.notNull(this.sourceOutput, "'sourceOutput' must not be null");
|
Assert.notNull(this.sourceOutput, "'sourceOutput' must not be null");
|
||||||
Assert.notNull(this.resourceOutput, "'resourceOutput' must not be null");
|
Assert.notNull(this.resourceOutput, "'resourceOutput' must not be null");
|
||||||
Assert.notNull(this.classOutput, "'classOutput' must not be null");
|
Assert.notNull(this.classOutput, "'classOutput' must not be null");
|
||||||
Assert.hasText(this.groupId, "'groupId' must not be null or empty");
|
Assert.notNull(this.groupId, "'groupId' must not be null");
|
||||||
Assert.hasText(this.artifactId, "'artifactId' must not be null or empty");
|
Assert.notNull(this.artifactId, "'artifactId' must not be null");
|
||||||
return new Settings(this.sourceOutput, this.resourceOutput, this.classOutput,
|
return new Settings(this.sourceOutput, this.resourceOutput, this.classOutput,
|
||||||
this.groupId, this.artifactId);
|
this.groupId, this.artifactId);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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.
|
||||||
|
@ -318,8 +318,8 @@ public class ApplicationListenerMethodAdapter implements GenericApplicationListe
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void publishEvents(Object result) {
|
private void publishEvents(@Nullable Object result) {
|
||||||
if (result.getClass().isArray()) {
|
if (result != null && result.getClass().isArray()) {
|
||||||
Object[] events = ObjectUtils.toObjectArray(result);
|
Object[] events = ObjectUtils.toObjectArray(result);
|
||||||
for (Object event : events) {
|
for (Object event : events) {
|
||||||
publishEvent(event);
|
publishEvent(event);
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2017 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.
|
||||||
|
@ -83,18 +83,21 @@ public class MBeanProxyFactoryBean extends MBeanClientInterceptor
|
||||||
public void afterPropertiesSet() throws MBeanServerNotFoundException, MBeanInfoRetrievalException {
|
public void afterPropertiesSet() throws MBeanServerNotFoundException, MBeanInfoRetrievalException {
|
||||||
super.afterPropertiesSet();
|
super.afterPropertiesSet();
|
||||||
|
|
||||||
|
Class<?> interfaceToUse;
|
||||||
if (this.proxyInterface == null) {
|
if (this.proxyInterface == null) {
|
||||||
this.proxyInterface = getManagementInterface();
|
interfaceToUse = getManagementInterface();
|
||||||
if (this.proxyInterface == null) {
|
if (interfaceToUse == null) {
|
||||||
throw new IllegalArgumentException("Property 'proxyInterface' or 'managementInterface' is required");
|
throw new IllegalArgumentException("Property 'proxyInterface' or 'managementInterface' is required");
|
||||||
}
|
}
|
||||||
|
this.proxyInterface = interfaceToUse;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
interfaceToUse = this.proxyInterface;
|
||||||
if (getManagementInterface() == null) {
|
if (getManagementInterface() == null) {
|
||||||
setManagementInterface(this.proxyInterface);
|
setManagementInterface(interfaceToUse);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.mbeanProxy = new ProxyFactory(this.proxyInterface, this).getProxy(this.beanClassLoader);
|
this.mbeanProxy = new ProxyFactory(interfaceToUse, this).getProxy(this.beanClassLoader);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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.
|
||||||
|
@ -1035,7 +1035,7 @@ public class DataBinder implements PropertyEditorRegistry, TypeConverter {
|
||||||
Class<?> constructorClass, String nestedPath, String name, @Nullable Object value) {
|
Class<?> constructorClass, String nestedPath, String name, @Nullable Object value) {
|
||||||
|
|
||||||
Object[] hints = null;
|
Object[] hints = null;
|
||||||
if (this.targetType.getSource() instanceof MethodParameter parameter) {
|
if (this.targetType != null && this.targetType.getSource() instanceof MethodParameter parameter) {
|
||||||
for (Annotation ann : parameter.getParameterAnnotations()) {
|
for (Annotation ann : parameter.getParameterAnnotations()) {
|
||||||
hints = ValidationAnnotationUtils.determineValidationHints(ann);
|
hints = ValidationAnnotationUtils.determineValidationHints(ann);
|
||||||
if (hints != null) {
|
if (hints != null) {
|
||||||
|
|
|
@ -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.
|
||||||
|
@ -79,8 +79,8 @@ import org.springframework.validation.method.ParameterValidationResult;
|
||||||
*/
|
*/
|
||||||
public class MethodValidationInterceptor implements MethodInterceptor {
|
public class MethodValidationInterceptor implements MethodInterceptor {
|
||||||
|
|
||||||
private static final boolean REACTOR_PRESENT =
|
private static final boolean reactorPresent = ClassUtils.isPresent(
|
||||||
ClassUtils.isPresent("reactor.core.publisher.Mono", MethodValidationInterceptor.class.getClassLoader());
|
"reactor.core.publisher.Mono", MethodValidationInterceptor.class.getClassLoader());
|
||||||
|
|
||||||
|
|
||||||
private final MethodValidationAdapter validationAdapter;
|
private final MethodValidationAdapter validationAdapter;
|
||||||
|
@ -153,7 +153,7 @@ public class MethodValidationInterceptor implements MethodInterceptor {
|
||||||
Object[] arguments = invocation.getArguments();
|
Object[] arguments = invocation.getArguments();
|
||||||
Class<?>[] groups = determineValidationGroups(invocation);
|
Class<?>[] groups = determineValidationGroups(invocation);
|
||||||
|
|
||||||
if (REACTOR_PRESENT) {
|
if (reactorPresent) {
|
||||||
arguments = ReactorValidationHelper.insertAsyncValidation(
|
arguments = ReactorValidationHelper.insertAsyncValidation(
|
||||||
this.validationAdapter.getSpringValidatorAdapter(), this.adaptViolations,
|
this.validationAdapter.getSpringValidatorAdapter(), this.adaptViolations,
|
||||||
target, method, arguments);
|
target, method, arguments);
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2022 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.
|
||||||
|
@ -53,7 +53,7 @@ public class DefaultMethodReference implements MethodReference {
|
||||||
public CodeBlock toCodeBlock() {
|
public CodeBlock toCodeBlock() {
|
||||||
String methodName = this.method.name;
|
String methodName = this.method.name;
|
||||||
if (isStatic()) {
|
if (isStatic()) {
|
||||||
Assert.state(this.declaringClass != null, "static method reference must define a declaring class");
|
Assert.state(this.declaringClass != null, "Static method reference must define a declaring class");
|
||||||
return CodeBlock.of("$T::$L", this.declaringClass, methodName);
|
return CodeBlock.of("$T::$L", this.declaringClass, methodName);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -64,11 +64,12 @@ public class DefaultMethodReference implements MethodReference {
|
||||||
@Override
|
@Override
|
||||||
public CodeBlock toInvokeCodeBlock(ArgumentCodeGenerator argumentCodeGenerator,
|
public CodeBlock toInvokeCodeBlock(ArgumentCodeGenerator argumentCodeGenerator,
|
||||||
@Nullable ClassName targetClassName) {
|
@Nullable ClassName targetClassName) {
|
||||||
|
|
||||||
String methodName = this.method.name;
|
String methodName = this.method.name;
|
||||||
CodeBlock.Builder code = CodeBlock.builder();
|
CodeBlock.Builder code = CodeBlock.builder();
|
||||||
if (isStatic()) {
|
if (isStatic()) {
|
||||||
Assert.state(this.declaringClass != null, "static method reference must define a declaring class");
|
Assert.state(this.declaringClass != null, "Static method reference must define a declaring class");
|
||||||
if (isSameDeclaringClass(targetClassName)) {
|
if (this.declaringClass.equals(targetClassName)) {
|
||||||
code.add("$L", methodName);
|
code.add("$L", methodName);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -76,7 +77,7 @@ public class DefaultMethodReference implements MethodReference {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (!isSameDeclaringClass(targetClassName)) {
|
if (this.declaringClass != null && !this.declaringClass.equals(targetClassName)) {
|
||||||
code.add(instantiateDeclaringClass(this.declaringClass));
|
code.add(instantiateDeclaringClass(this.declaringClass));
|
||||||
}
|
}
|
||||||
code.add("$L", methodName);
|
code.add("$L", methodName);
|
||||||
|
@ -117,10 +118,6 @@ public class DefaultMethodReference implements MethodReference {
|
||||||
return this.method.modifiers.contains(Modifier.STATIC);
|
return this.method.modifiers.contains(Modifier.STATIC);
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isSameDeclaringClass(ClassName declaringClass) {
|
|
||||||
return this.declaringClass == null || this.declaringClass.equals(declaringClass);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
String methodName = this.method.name;
|
String methodName = this.method.name;
|
||||||
|
@ -128,7 +125,7 @@ public class DefaultMethodReference implements MethodReference {
|
||||||
return this.declaringClass + "::" + methodName;
|
return this.declaringClass + "::" + methodName;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return ((this.declaringClass != null) ?
|
return (this.declaringClass != null ?
|
||||||
"<" + this.declaringClass + ">" : "<instance>") + "::" + methodName;
|
"<" + this.declaringClass + ">" : "<instance>") + "::" + methodName;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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.
|
||||||
|
@ -194,6 +194,7 @@ public class ReflectionHintsPredicates {
|
||||||
return new FieldHintPredicate(field);
|
return new FieldHintPredicate(field);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static class TypeHintPredicate implements Predicate<RuntimeHints> {
|
public static class TypeHintPredicate implements Predicate<RuntimeHints> {
|
||||||
|
|
||||||
private final TypeReference type;
|
private final TypeReference type;
|
||||||
|
@ -212,7 +213,6 @@ public class ReflectionHintsPredicates {
|
||||||
return getTypeHint(hints) != null;
|
return getTypeHint(hints) != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Refine the current predicate to only match if the given {@link MemberCategory} is present.
|
* Refine the current predicate to only match if the given {@link MemberCategory} is present.
|
||||||
* @param memberCategory the member category
|
* @param memberCategory the member category
|
||||||
|
@ -220,7 +220,10 @@ public class ReflectionHintsPredicates {
|
||||||
*/
|
*/
|
||||||
public Predicate<RuntimeHints> withMemberCategory(MemberCategory memberCategory) {
|
public Predicate<RuntimeHints> withMemberCategory(MemberCategory memberCategory) {
|
||||||
Assert.notNull(memberCategory, "'memberCategory' must not be null");
|
Assert.notNull(memberCategory, "'memberCategory' must not be null");
|
||||||
return this.and(hints -> getTypeHint(hints).getMemberCategories().contains(memberCategory));
|
return and(hints -> {
|
||||||
|
TypeHint hint = getTypeHint(hints);
|
||||||
|
return (hint != null && hint.getMemberCategories().contains(memberCategory));
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -230,7 +233,10 @@ public class ReflectionHintsPredicates {
|
||||||
*/
|
*/
|
||||||
public Predicate<RuntimeHints> withMemberCategories(MemberCategory... memberCategories) {
|
public Predicate<RuntimeHints> withMemberCategories(MemberCategory... memberCategories) {
|
||||||
Assert.notEmpty(memberCategories, "'memberCategories' must not be empty");
|
Assert.notEmpty(memberCategories, "'memberCategories' must not be empty");
|
||||||
return this.and(hints -> getTypeHint(hints).getMemberCategories().containsAll(Arrays.asList(memberCategories)));
|
return and(hints -> {
|
||||||
|
TypeHint hint = getTypeHint(hints);
|
||||||
|
return (hint != null && hint.getMemberCategories().containsAll(Arrays.asList(memberCategories)));
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -240,11 +246,14 @@ public class ReflectionHintsPredicates {
|
||||||
*/
|
*/
|
||||||
public Predicate<RuntimeHints> withAnyMemberCategory(MemberCategory... memberCategories) {
|
public Predicate<RuntimeHints> withAnyMemberCategory(MemberCategory... memberCategories) {
|
||||||
Assert.notEmpty(memberCategories, "'memberCategories' must not be empty");
|
Assert.notEmpty(memberCategories, "'memberCategories' must not be empty");
|
||||||
return this.and(hints -> Arrays.stream(memberCategories)
|
return and(hints -> {
|
||||||
.anyMatch(memberCategory -> getTypeHint(hints).getMemberCategories().contains(memberCategory)));
|
TypeHint hint = getTypeHint(hints);
|
||||||
|
return (hint != null && Arrays.stream(memberCategories)
|
||||||
|
.anyMatch(memberCategory -> hint.getMemberCategories().contains(memberCategory)));
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public abstract static class ExecutableHintPredicate<T extends Executable> implements Predicate<RuntimeHints> {
|
public abstract static class ExecutableHintPredicate<T extends Executable> implements Predicate<RuntimeHints> {
|
||||||
|
|
||||||
|
@ -289,6 +298,7 @@ public class ReflectionHintsPredicates {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static class ConstructorHintPredicate extends ExecutableHintPredicate<Constructor<?>> {
|
public static class ConstructorHintPredicate extends ExecutableHintPredicate<Constructor<?>> {
|
||||||
|
|
||||||
ConstructorHintPredicate(Constructor<?> constructor) {
|
ConstructorHintPredicate(Constructor<?> constructor) {
|
||||||
|
@ -322,14 +332,16 @@ public class ReflectionHintsPredicates {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
Predicate<RuntimeHints> exactMatch() {
|
Predicate<RuntimeHints> exactMatch() {
|
||||||
return hints -> (hints.reflection().getTypeHint(this.executable.getDeclaringClass()) != null) &&
|
return hints -> {
|
||||||
hints.reflection().getTypeHint(this.executable.getDeclaringClass()).constructors().anyMatch(executableHint -> {
|
TypeHint hint = hints.reflection().getTypeHint(this.executable.getDeclaringClass());
|
||||||
|
return (hint != null && hint.constructors().anyMatch(executableHint -> {
|
||||||
List<TypeReference> parameters = TypeReference.listOf(this.executable.getParameterTypes());
|
List<TypeReference> parameters = TypeReference.listOf(this.executable.getParameterTypes());
|
||||||
return includes(executableHint, "<init>", parameters, this.executableMode);
|
return includes(executableHint, "<init>", parameters, this.executableMode);
|
||||||
});
|
}));
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class MethodHintPredicate extends ExecutableHintPredicate<Method> {
|
public static class MethodHintPredicate extends ExecutableHintPredicate<Method> {
|
||||||
|
|
||||||
|
@ -367,14 +379,16 @@ public class ReflectionHintsPredicates {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
Predicate<RuntimeHints> exactMatch() {
|
Predicate<RuntimeHints> exactMatch() {
|
||||||
return hints -> (hints.reflection().getTypeHint(this.executable.getDeclaringClass()) != null) &&
|
return hints -> {
|
||||||
hints.reflection().getTypeHint(this.executable.getDeclaringClass()).methods().anyMatch(executableHint -> {
|
TypeHint hint = hints.reflection().getTypeHint(this.executable.getDeclaringClass());
|
||||||
|
return (hint != null && hint.methods().anyMatch(executableHint -> {
|
||||||
List<TypeReference> parameters = TypeReference.listOf(this.executable.getParameterTypes());
|
List<TypeReference> parameters = TypeReference.listOf(this.executable.getParameterTypes());
|
||||||
return includes(executableHint, this.executable.getName(), parameters, this.executableMode);
|
return includes(executableHint, this.executable.getName(), parameters, this.executableMode);
|
||||||
});
|
}));
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class FieldHintPredicate implements Predicate<RuntimeHints> {
|
public static class FieldHintPredicate implements Predicate<RuntimeHints> {
|
||||||
|
|
||||||
|
@ -406,7 +420,6 @@ public class ReflectionHintsPredicates {
|
||||||
return typeHint.fields().anyMatch(fieldHint ->
|
return typeHint.fields().anyMatch(fieldHint ->
|
||||||
this.field.getName().equals(fieldHint.getName()));
|
this.field.getName().equals(fieldHint.getName()));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,6 +46,7 @@ import org.reactivestreams.Publisher;
|
||||||
import reactor.core.publisher.Flux;
|
import reactor.core.publisher.Flux;
|
||||||
import reactor.core.publisher.Mono;
|
import reactor.core.publisher.Mono;
|
||||||
|
|
||||||
|
import org.springframework.lang.Nullable;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
import org.springframework.util.CollectionUtils;
|
import org.springframework.util.CollectionUtils;
|
||||||
|
|
||||||
|
@ -64,6 +65,7 @@ public abstract class CoroutinesUtils {
|
||||||
|
|
||||||
private static final KType publisherType = KClassifiers.getStarProjectedType(JvmClassMappingKt.getKotlinClass(Publisher.class));
|
private static final KType publisherType = KClassifiers.getStarProjectedType(JvmClassMappingKt.getKotlinClass(Publisher.class));
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convert a {@link Deferred} instance to a {@link Mono}.
|
* Convert a {@link Deferred} instance to a {@link Mono}.
|
||||||
*/
|
*/
|
||||||
|
@ -109,9 +111,10 @@ public abstract class CoroutinesUtils {
|
||||||
* @since 6.0
|
* @since 6.0
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings({"deprecation", "DataFlowIssue"})
|
@SuppressWarnings({"deprecation", "DataFlowIssue"})
|
||||||
public static Publisher<?> invokeSuspendingFunction(CoroutineContext context, Method method, Object target,
|
public static Publisher<?> invokeSuspendingFunction(
|
||||||
Object... args) {
|
CoroutineContext context, Method method, @Nullable Object target, Object... args) {
|
||||||
Assert.isTrue(KotlinDetector.isSuspendingFunction(method), "'method' must be a suspending function");
|
|
||||||
|
Assert.isTrue(KotlinDetector.isSuspendingFunction(method), "Method must be a suspending function");
|
||||||
KFunction<?> function = Objects.requireNonNull(ReflectJvmMapping.getKotlinFunction(method));
|
KFunction<?> function = Objects.requireNonNull(ReflectJvmMapping.getKotlinFunction(method));
|
||||||
if (method.isAccessible() && !KCallablesJvm.isAccessible(function)) {
|
if (method.isAccessible() && !KCallablesJvm.isAccessible(function)) {
|
||||||
KCallablesJvm.setAccessible(function, true);
|
KCallablesJvm.setAccessible(function, true);
|
||||||
|
|
|
@ -650,11 +650,10 @@ public abstract class AnnotationUtils {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (Class<?>) MergedAnnotations.from(clazz, SearchStrategy.SUPERCLASS)
|
MergedAnnotation<?> merged = MergedAnnotations.from(clazz, SearchStrategy.SUPERCLASS).stream()
|
||||||
.stream()
|
|
||||||
.filter(MergedAnnotationPredicates.typeIn(annotationTypes).and(MergedAnnotation::isDirectlyPresent))
|
.filter(MergedAnnotationPredicates.typeIn(annotationTypes).and(MergedAnnotation::isDirectlyPresent))
|
||||||
.map(MergedAnnotation::getSource)
|
|
||||||
.findFirst().orElse(null);
|
.findFirst().orElse(null);
|
||||||
|
return (merged != null && merged.getSource() instanceof Class<?> sourceClass ? sourceClass : null);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2021 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.
|
||||||
|
@ -167,6 +167,7 @@ final class MergedAnnotationsCollection implements MergedAnnotations {
|
||||||
MergedAnnotation<A> result = null;
|
MergedAnnotation<A> result = null;
|
||||||
for (int i = 0; i < this.annotations.length; i++) {
|
for (int i = 0; i < this.annotations.length; i++) {
|
||||||
MergedAnnotation<?> root = this.annotations[i];
|
MergedAnnotation<?> root = this.annotations[i];
|
||||||
|
if (root != null) {
|
||||||
AnnotationTypeMappings mappings = this.mappings[i];
|
AnnotationTypeMappings mappings = this.mappings[i];
|
||||||
for (int mappingIndex = 0; mappingIndex < mappings.size(); mappingIndex++) {
|
for (int mappingIndex = 0; mappingIndex < mappings.size(); mappingIndex++) {
|
||||||
AnnotationTypeMapping mapping = mappings.get(mappingIndex);
|
AnnotationTypeMapping mapping = mappings.get(mappingIndex);
|
||||||
|
@ -183,6 +184,7 @@ final class MergedAnnotationsCollection implements MergedAnnotations {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -28,7 +28,7 @@ import org.springframework.lang.Nullable;
|
||||||
* @author Sebastien Deleuze
|
* @author Sebastien Deleuze
|
||||||
* @since 6.1
|
* @since 6.1
|
||||||
*/
|
*/
|
||||||
class StringToRegexConverter implements Converter<String, Regex> {
|
final class StringToRegexConverter implements Converter<String, Regex> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Nullable
|
@Nullable
|
||||||
|
|
|
@ -1113,13 +1113,13 @@ public abstract class DataBufferUtils {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void failed(Throwable exc, Attachment attachment) {
|
public void failed(Throwable ex, Attachment attachment) {
|
||||||
attachment.iterator().close();
|
attachment.iterator().close();
|
||||||
release(attachment.dataBuffer());
|
release(attachment.dataBuffer());
|
||||||
|
|
||||||
closeChannel(this.channel);
|
closeChannel(this.channel);
|
||||||
this.state.set(State.DISPOSED);
|
this.state.set(State.DISPOSED);
|
||||||
this.sink.error(exc);
|
this.sink.error(ex);
|
||||||
}
|
}
|
||||||
|
|
||||||
private enum State {
|
private enum State {
|
||||||
|
@ -1178,7 +1178,6 @@ public abstract class DataBufferUtils {
|
||||||
public Context currentContext() {
|
public Context currentContext() {
|
||||||
return Context.of(this.sink.contextView());
|
return Context.of(this.sink.contextView());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1273,13 +1272,13 @@ public abstract class DataBufferUtils {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void failed(Throwable exc, Attachment attachment) {
|
public void failed(Throwable ex, Attachment attachment) {
|
||||||
attachment.iterator().close();
|
attachment.iterator().close();
|
||||||
|
|
||||||
this.sink.next(attachment.dataBuffer());
|
this.sink.next(attachment.dataBuffer());
|
||||||
this.writing.set(false);
|
this.writing.set(false);
|
||||||
|
|
||||||
this.sink.error(exc);
|
this.sink.error(ex);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -1288,9 +1287,6 @@ public abstract class DataBufferUtils {
|
||||||
}
|
}
|
||||||
|
|
||||||
private record Attachment(ByteBuffer byteBuffer, DataBuffer dataBuffer, DataBuffer.ByteBufferIterator iterator) {}
|
private record Attachment(ByteBuffer byteBuffer, DataBuffer dataBuffer, DataBuffer.ByteBufferIterator iterator) {}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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.
|
||||||
|
@ -178,13 +178,14 @@ final class OutputStreamPublisher implements Publisher<DataBuffer> {
|
||||||
if (isCancelled(previousState)) {
|
if (isCancelled(previousState)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isTerminated(previousState)) {
|
if (isTerminated(previousState)) {
|
||||||
// failure due to illegal requestN
|
// failure due to illegal requestN
|
||||||
this.actual.onError(this.error);
|
Throwable error = this.error;
|
||||||
|
if (error != null) {
|
||||||
|
this.actual.onError(error);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
this.actual.onError(ex);
|
this.actual.onError(ex);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -193,13 +194,14 @@ final class OutputStreamPublisher implements Publisher<DataBuffer> {
|
||||||
if (isCancelled(previousState)) {
|
if (isCancelled(previousState)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isTerminated(previousState)) {
|
if (isTerminated(previousState)) {
|
||||||
// failure due to illegal requestN
|
// failure due to illegal requestN
|
||||||
this.actual.onError(this.error);
|
Throwable error = this.error;
|
||||||
|
if (error != null) {
|
||||||
|
this.actual.onError(error);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
this.actual.onComplete();
|
this.actual.onComplete();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -209,16 +211,13 @@ final class OutputStreamPublisher implements Publisher<DataBuffer> {
|
||||||
if (n <= 0) {
|
if (n <= 0) {
|
||||||
this.error = new IllegalArgumentException("request should be a positive number");
|
this.error = new IllegalArgumentException("request should be a positive number");
|
||||||
long previousState = tryTerminate();
|
long previousState = tryTerminate();
|
||||||
|
|
||||||
if (isTerminated(previousState) || isCancelled(previousState)) {
|
if (isTerminated(previousState) || isCancelled(previousState)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (previousState > 0) {
|
if (previousState > 0) {
|
||||||
// error should eventually be observed and propagated
|
// error should eventually be observed and propagated
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// resume parked thread, so it can observe error and propagate it
|
// resume parked thread, so it can observe error and propagate it
|
||||||
resume();
|
resume();
|
||||||
return;
|
return;
|
||||||
|
@ -276,11 +275,9 @@ final class OutputStreamPublisher implements Publisher<DataBuffer> {
|
||||||
private long tryCancel() {
|
private long tryCancel() {
|
||||||
while (true) {
|
while (true) {
|
||||||
long r = this.requested.get();
|
long r = this.requested.get();
|
||||||
|
|
||||||
if (isCancelled(r)) {
|
if (isCancelled(r)) {
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.requested.compareAndSet(r, Long.MIN_VALUE)) {
|
if (this.requested.compareAndSet(r, Long.MIN_VALUE)) {
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
@ -290,11 +287,9 @@ final class OutputStreamPublisher implements Publisher<DataBuffer> {
|
||||||
private long tryTerminate() {
|
private long tryTerminate() {
|
||||||
while (true) {
|
while (true) {
|
||||||
long r = this.requested.get();
|
long r = this.requested.get();
|
||||||
|
|
||||||
if (isCancelled(r) || isTerminated(r)) {
|
if (isCancelled(r) || isTerminated(r)) {
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.requested.compareAndSet(r, Long.MIN_VALUE | Long.MAX_VALUE)) {
|
if (this.requested.compareAndSet(r, Long.MIN_VALUE | Long.MAX_VALUE)) {
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
|
@ -557,7 +557,7 @@ public abstract class ClassUtils {
|
||||||
* @see Void
|
* @see Void
|
||||||
* @see Void#TYPE
|
* @see Void#TYPE
|
||||||
*/
|
*/
|
||||||
public static boolean isVoidType(Class<?> type) {
|
public static boolean isVoidType(@Nullable Class<?> type) {
|
||||||
return (type == void.class || type == Void.class);
|
return (type == void.class || type == Void.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2022 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.
|
||||||
|
@ -99,7 +99,9 @@ public abstract class SerializationUtils {
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public static <T extends Serializable> T clone(T object) {
|
public static <T extends Serializable> T clone(T object) {
|
||||||
return (T) SerializationUtils.deserialize(SerializationUtils.serialize(object));
|
Object result = SerializationUtils.deserialize(SerializationUtils.serialize(object));
|
||||||
|
Assert.state(result != null, "Deserialized object must not be null");
|
||||||
|
return (T) result;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2022 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.
|
||||||
|
@ -88,7 +88,7 @@ class DefaultMethodReferenceTests {
|
||||||
MethodSpec method = createTestMethod("methodName", new TypeName[0], Modifier.STATIC);
|
MethodSpec method = createTestMethod("methodName", new TypeName[0], Modifier.STATIC);
|
||||||
MethodReference methodReference = new DefaultMethodReference(method, null);
|
MethodReference methodReference = new DefaultMethodReference(method, null);
|
||||||
assertThatIllegalStateException().isThrownBy(methodReference::toCodeBlock)
|
assertThatIllegalStateException().isThrownBy(methodReference::toCodeBlock)
|
||||||
.withMessage("static method reference must define a declaring class");
|
.withMessage("Static method reference must define a declaring class");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
|
@ -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.
|
||||||
|
@ -230,7 +230,7 @@ public class ConstructorReference extends SpelNodeImpl {
|
||||||
InlineList initializer = (InlineList) getChild(1);
|
InlineList initializer = (InlineList) getChild(1);
|
||||||
sb.append("[] ").append(initializer.toStringAST());
|
sb.append("[] ").append(initializer.toStringAST());
|
||||||
}
|
}
|
||||||
else {
|
else if (this.dimensions != null) {
|
||||||
// new int[3], new java.lang.String[3][4], etc.
|
// new int[3], new java.lang.String[3][4], etc.
|
||||||
for (SpelNodeImpl dimension : this.dimensions) {
|
for (SpelNodeImpl dimension : this.dimensions) {
|
||||||
sb.append('[').append(dimension.toStringAST()).append(']');
|
sb.append('[').append(dimension.toStringAST()).append(']');
|
||||||
|
|
|
@ -222,7 +222,9 @@ public class Indexer extends SpelNodeImpl {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.indexedType == IndexedType.ARRAY) {
|
if (this.indexedType == IndexedType.ARRAY) {
|
||||||
int insn = switch (this.exitTypeDescriptor) {
|
String exitTypeDescriptor = this.exitTypeDescriptor;
|
||||||
|
Assert.state(exitTypeDescriptor != null, "Array not compilable without descriptor");
|
||||||
|
int insn = switch (exitTypeDescriptor) {
|
||||||
case "D" -> {
|
case "D" -> {
|
||||||
mv.visitTypeInsn(CHECKCAST, "[D");
|
mv.visitTypeInsn(CHECKCAST, "[D");
|
||||||
yield DALOAD;
|
yield DALOAD;
|
||||||
|
@ -258,8 +260,8 @@ public class Indexer extends SpelNodeImpl {
|
||||||
yield CALOAD;
|
yield CALOAD;
|
||||||
}
|
}
|
||||||
default -> {
|
default -> {
|
||||||
mv.visitTypeInsn(CHECKCAST, "["+ this.exitTypeDescriptor +
|
mv.visitTypeInsn(CHECKCAST, "["+ exitTypeDescriptor +
|
||||||
(CodeFlow.isPrimitiveArray(this.exitTypeDescriptor) ? "" : ";"));
|
(CodeFlow.isPrimitiveArray(exitTypeDescriptor) ? "" : ";"));
|
||||||
yield AALOAD;
|
yield AALOAD;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -55,7 +55,7 @@ class Token {
|
||||||
* @param startPos the exact start position
|
* @param startPos the exact start position
|
||||||
* @param endPos the index of the last character
|
* @param endPos the index of the last character
|
||||||
*/
|
*/
|
||||||
Token(TokenKind tokenKind, char[] tokenData, int startPos, int endPos) {
|
Token(TokenKind tokenKind, @Nullable char[] tokenData, int startPos, int endPos) {
|
||||||
this.kind = tokenKind;
|
this.kind = tokenKind;
|
||||||
this.data = (tokenData != null ? new String(tokenData) : null);
|
this.data = (tokenData != null ? new String(tokenData) : null);
|
||||||
this.startPos = startPos;
|
this.startPos = startPos;
|
||||||
|
|
|
@ -296,7 +296,8 @@ public abstract class ReflectionHelper {
|
||||||
TypeDescriptor sourceType = TypeDescriptor.forObject(argument);
|
TypeDescriptor sourceType = TypeDescriptor.forObject(argument);
|
||||||
if (argument == null) {
|
if (argument == null) {
|
||||||
// Perform the equivalent of GenericConversionService.convertNullSource() for a single argument.
|
// Perform the equivalent of GenericConversionService.convertNullSource() for a single argument.
|
||||||
if (targetType.getElementTypeDescriptor().getObjectType() == Optional.class) {
|
TypeDescriptor elementDesc = targetType.getElementTypeDescriptor();
|
||||||
|
if (elementDesc != null && elementDesc.getObjectType() == Optional.class) {
|
||||||
arguments[varargsPosition] = Optional.empty();
|
arguments[varargsPosition] = Optional.empty();
|
||||||
conversionOccurred = true;
|
conversionOccurred = true;
|
||||||
}
|
}
|
||||||
|
@ -383,7 +384,8 @@ public abstract class ReflectionHelper {
|
||||||
TypeDescriptor sourceType = TypeDescriptor.forObject(argument);
|
TypeDescriptor sourceType = TypeDescriptor.forObject(argument);
|
||||||
if (argument == null) {
|
if (argument == null) {
|
||||||
// Perform the equivalent of GenericConversionService.convertNullSource() for a single argument.
|
// Perform the equivalent of GenericConversionService.convertNullSource() for a single argument.
|
||||||
if (varArgContentType.getElementTypeDescriptor().getObjectType() == Optional.class) {
|
TypeDescriptor elementDesc = varArgContentType.getElementTypeDescriptor();
|
||||||
|
if (elementDesc != null && elementDesc.getObjectType() == Optional.class) {
|
||||||
arguments[varargsPosition] = Optional.empty();
|
arguments[varargsPosition] = Optional.empty();
|
||||||
conversionOccurred = true;
|
conversionOccurred = true;
|
||||||
}
|
}
|
||||||
|
@ -408,7 +410,6 @@ public abstract class ReflectionHelper {
|
||||||
}
|
}
|
||||||
// Otherwise, convert remaining arguments to the varargs element type.
|
// Otherwise, convert remaining arguments to the varargs element type.
|
||||||
else {
|
else {
|
||||||
Assert.state(varArgContentType != null, "No element type");
|
|
||||||
for (int i = varargsPosition; i < arguments.length; i++) {
|
for (int i = varargsPosition; i < arguments.length; i++) {
|
||||||
Object argument = arguments[i];
|
Object argument = arguments[i];
|
||||||
arguments[i] = converter.convertValue(argument, TypeDescriptor.forObject(argument), varArgContentType);
|
arguments[i] = converter.convertValue(argument, TypeDescriptor.forObject(argument), varArgContentType);
|
||||||
|
|
|
@ -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.
|
||||||
|
@ -88,6 +88,10 @@ public final class CallMetaDataProviderFactory {
|
||||||
try {
|
try {
|
||||||
return JdbcUtils.extractDatabaseMetaData(dataSource, databaseMetaData -> {
|
return JdbcUtils.extractDatabaseMetaData(dataSource, databaseMetaData -> {
|
||||||
String databaseProductName = JdbcUtils.commonDatabaseName(databaseMetaData.getDatabaseProductName());
|
String databaseProductName = JdbcUtils.commonDatabaseName(databaseMetaData.getDatabaseProductName());
|
||||||
|
if (databaseProductName == null) {
|
||||||
|
databaseProductName = "";
|
||||||
|
}
|
||||||
|
|
||||||
boolean accessProcedureColumnMetaData = context.isAccessCallParameterMetaData();
|
boolean accessProcedureColumnMetaData = context.isAccessCallParameterMetaData();
|
||||||
if (context.isFunction()) {
|
if (context.isFunction()) {
|
||||||
if (!supportedDatabaseProductsForFunctions.contains(databaseProductName)) {
|
if (!supportedDatabaseProductsForFunctions.contains(databaseProductName)) {
|
||||||
|
|
|
@ -438,7 +438,7 @@ public class TableMetaDataContext {
|
||||||
this.quoting = StringUtils.hasText(identifierQuoteString);
|
this.quoting = StringUtils.hasText(identifierQuoteString);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void appendTo(StringBuilder stringBuilder, String item) {
|
public void appendTo(StringBuilder stringBuilder, @Nullable String item) {
|
||||||
if (this.quoting) {
|
if (this.quoting) {
|
||||||
stringBuilder.append(this.identifierQuoteString)
|
stringBuilder.append(this.identifierQuoteString)
|
||||||
.append(item).append(this.identifierQuoteString);
|
.append(item).append(this.identifierQuoteString);
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2017 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.
|
||||||
|
@ -84,8 +84,9 @@ public class EmbeddedDatabaseFactoryBean extends EmbeddedDatabaseFactory
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void destroy() {
|
public void destroy() {
|
||||||
if (this.databaseCleaner != null && getDataSource() != null) {
|
DatabasePopulator cleaner = this.databaseCleaner;
|
||||||
DatabasePopulatorUtils.execute(this.databaseCleaner, getDataSource());
|
if (cleaner != null && getDataSource() != null) {
|
||||||
|
DatabasePopulatorUtils.execute(cleaner, getDataSource());
|
||||||
}
|
}
|
||||||
shutdownDatabase();
|
shutdownDatabase();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2022 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.
|
||||||
|
@ -309,9 +309,10 @@ class ChannelSendOperator<T> extends Mono<Void> implements Scannable {
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean emitCachedSignals() {
|
private boolean emitCachedSignals() {
|
||||||
if (this.error != null) {
|
Throwable error = this.error;
|
||||||
|
if (error != null) {
|
||||||
try {
|
try {
|
||||||
requiredWriteSubscriber().onError(this.error);
|
requiredWriteSubscriber().onError(error);
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
releaseCachedItem();
|
releaseCachedItem();
|
||||||
|
|
|
@ -33,7 +33,6 @@ import org.springframework.core.MethodParameter;
|
||||||
import org.springframework.core.ParameterNameDiscoverer;
|
import org.springframework.core.ParameterNameDiscoverer;
|
||||||
import org.springframework.core.ReactiveAdapter;
|
import org.springframework.core.ReactiveAdapter;
|
||||||
import org.springframework.core.ReactiveAdapterRegistry;
|
import org.springframework.core.ReactiveAdapterRegistry;
|
||||||
import org.springframework.lang.Nullable;
|
|
||||||
import org.springframework.messaging.Message;
|
import org.springframework.messaging.Message;
|
||||||
import org.springframework.messaging.handler.HandlerMethod;
|
import org.springframework.messaging.handler.HandlerMethod;
|
||||||
import org.springframework.messaging.handler.invocation.MethodArgumentResolutionException;
|
import org.springframework.messaging.handler.invocation.MethodArgumentResolutionException;
|
||||||
|
@ -153,7 +152,7 @@ public class InvocableHandlerMethod extends HandlerMethod {
|
||||||
MethodParameter returnType = getReturnType();
|
MethodParameter returnType = getReturnType();
|
||||||
Class<?> reactiveType = (isSuspendingFunction ? value.getClass() : returnType.getParameterType());
|
Class<?> reactiveType = (isSuspendingFunction ? value.getClass() : returnType.getParameterType());
|
||||||
ReactiveAdapter adapter = this.reactiveAdapterRegistry.getAdapter(reactiveType);
|
ReactiveAdapter adapter = this.reactiveAdapterRegistry.getAdapter(reactiveType);
|
||||||
return (isAsyncVoidReturnType(returnType, adapter) ?
|
return (adapter != null && isAsyncVoidReturnType(returnType, adapter) ?
|
||||||
Mono.from(adapter.toPublisher(value)) : Mono.justOrEmpty(value));
|
Mono.from(adapter.toPublisher(value)) : Mono.justOrEmpty(value));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -200,8 +199,8 @@ public class InvocableHandlerMethod extends HandlerMethod {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isAsyncVoidReturnType(MethodParameter returnType, @Nullable ReactiveAdapter reactiveAdapter) {
|
private boolean isAsyncVoidReturnType(MethodParameter returnType, ReactiveAdapter reactiveAdapter) {
|
||||||
if (reactiveAdapter != null && reactiveAdapter.supportsEmpty()) {
|
if (reactiveAdapter.supportsEmpty()) {
|
||||||
if (reactiveAdapter.isNoValue()) {
|
if (reactiveAdapter.isNoValue()) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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.
|
||||||
|
@ -631,8 +631,9 @@ public class HibernateTransactionManager extends AbstractPlatformTransactionMana
|
||||||
TransactionSynchronizationManager.unbindResource(sessionFactory);
|
TransactionSynchronizationManager.unbindResource(sessionFactory);
|
||||||
}
|
}
|
||||||
TransactionSynchronizationManager.bindResource(sessionFactory, resourcesHolder.getSessionHolder());
|
TransactionSynchronizationManager.bindResource(sessionFactory, resourcesHolder.getSessionHolder());
|
||||||
if (getDataSource() != null && resourcesHolder.getConnectionHolder() != null) {
|
ConnectionHolder connectionHolder = resourcesHolder.getConnectionHolder();
|
||||||
TransactionSynchronizationManager.bindResource(getDataSource(), resourcesHolder.getConnectionHolder());
|
if (connectionHolder != null && getDataSource() != null) {
|
||||||
|
TransactionSynchronizationManager.bindResource(getDataSource(), connectionHolder);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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.
|
||||||
|
@ -535,8 +535,9 @@ public class JpaTransactionManager extends AbstractPlatformTransactionManager
|
||||||
SuspendedResourcesHolder resourcesHolder = (SuspendedResourcesHolder) suspendedResources;
|
SuspendedResourcesHolder resourcesHolder = (SuspendedResourcesHolder) suspendedResources;
|
||||||
TransactionSynchronizationManager.bindResource(
|
TransactionSynchronizationManager.bindResource(
|
||||||
obtainEntityManagerFactory(), resourcesHolder.getEntityManagerHolder());
|
obtainEntityManagerFactory(), resourcesHolder.getEntityManagerHolder());
|
||||||
if (getDataSource() != null && resourcesHolder.getConnectionHolder() != null) {
|
ConnectionHolder connectionHolder = resourcesHolder.getConnectionHolder();
|
||||||
TransactionSynchronizationManager.bindResource(getDataSource(), resourcesHolder.getConnectionHolder());
|
if (connectionHolder != null && getDataSource() != null) {
|
||||||
|
TransactionSynchronizationManager.bindResource(getDataSource(), connectionHolder);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2022 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.
|
||||||
|
@ -42,14 +42,14 @@ final class GeneratedMapUtils {
|
||||||
* @param methodName the name of the static method to invoke
|
* @param methodName the name of the static method to invoke
|
||||||
* @return an unmodifiable map retrieved from a static method
|
* @return an unmodifiable map retrieved from a static method
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings({ "rawtypes", "unchecked" })
|
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||||
static Map loadMap(String className, String methodName) {
|
static Map loadMap(String className, String methodName) {
|
||||||
try {
|
try {
|
||||||
Class<?> clazz = ClassUtils.forName(className, null);
|
Class<?> clazz = ClassUtils.forName(className, null);
|
||||||
Method method = ReflectionUtils.findMethod(clazz, methodName);
|
Method method = ReflectionUtils.findMethod(clazz, methodName);
|
||||||
Assert.state(method != null, () -> "No %s() method found in %s".formatted(methodName, className));
|
Assert.state(method != null, () -> "No %s() method found in %s".formatted(methodName, className));
|
||||||
Map map = (Map) ReflectionUtils.invokeMethod(method, null);
|
Map map = (Map) ReflectionUtils.invokeMethod(method, null);
|
||||||
return Collections.unmodifiableMap(map);
|
return (map != null ? Collections.unmodifiableMap(map) : Collections.emptyMap());
|
||||||
}
|
}
|
||||||
catch (IllegalStateException ex) {
|
catch (IllegalStateException ex) {
|
||||||
throw ex;
|
throw ex;
|
||||||
|
|
|
@ -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.
|
||||||
|
@ -20,6 +20,7 @@ import org.springframework.aot.generate.ClassNameGenerator;
|
||||||
import org.springframework.aot.generate.DefaultGenerationContext;
|
import org.springframework.aot.generate.DefaultGenerationContext;
|
||||||
import org.springframework.aot.generate.GeneratedFiles;
|
import org.springframework.aot.generate.GeneratedFiles;
|
||||||
import org.springframework.aot.hint.RuntimeHints;
|
import org.springframework.aot.hint.RuntimeHints;
|
||||||
|
import org.springframework.lang.Nullable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Extension of {@link DefaultGenerationContext} with a custom implementation of
|
* Extension of {@link DefaultGenerationContext} with a custom implementation of
|
||||||
|
@ -30,6 +31,7 @@ import org.springframework.aot.hint.RuntimeHints;
|
||||||
*/
|
*/
|
||||||
class TestContextGenerationContext extends DefaultGenerationContext {
|
class TestContextGenerationContext extends DefaultGenerationContext {
|
||||||
|
|
||||||
|
@Nullable
|
||||||
private final String featureName;
|
private final String featureName;
|
||||||
|
|
||||||
|
|
||||||
|
@ -41,8 +43,9 @@ class TestContextGenerationContext extends DefaultGenerationContext {
|
||||||
* @param generatedFiles the generated files
|
* @param generatedFiles the generated files
|
||||||
* @param runtimeHints the runtime hints
|
* @param runtimeHints the runtime hints
|
||||||
*/
|
*/
|
||||||
TestContextGenerationContext(ClassNameGenerator classNameGenerator, GeneratedFiles generatedFiles,
|
TestContextGenerationContext(
|
||||||
RuntimeHints runtimeHints) {
|
ClassNameGenerator classNameGenerator, GeneratedFiles generatedFiles, RuntimeHints runtimeHints) {
|
||||||
|
|
||||||
super(classNameGenerator, generatedFiles, runtimeHints);
|
super(classNameGenerator, generatedFiles, runtimeHints);
|
||||||
this.featureName = null;
|
this.featureName = null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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.
|
||||||
|
@ -25,6 +25,7 @@ import org.apache.commons.logging.LogFactory;
|
||||||
|
|
||||||
import org.springframework.context.ApplicationContext;
|
import org.springframework.context.ApplicationContext;
|
||||||
import org.springframework.core.Conventions;
|
import org.springframework.core.Conventions;
|
||||||
|
import org.springframework.lang.Nullable;
|
||||||
import org.springframework.test.context.TestContext;
|
import org.springframework.test.context.TestContext;
|
||||||
import org.springframework.test.context.support.AbstractTestExecutionListener;
|
import org.springframework.test.context.support.AbstractTestExecutionListener;
|
||||||
import org.springframework.util.ReflectionUtils;
|
import org.springframework.util.ReflectionUtils;
|
||||||
|
@ -67,6 +68,7 @@ class MicrometerObservationRegistryTestExecutionListener extends AbstractTestExe
|
||||||
static final String OBSERVATION_THREAD_LOCAL_ACCESSOR_CLASS_NAME =
|
static final String OBSERVATION_THREAD_LOCAL_ACCESSOR_CLASS_NAME =
|
||||||
"io.micrometer.observation.contextpropagation.ObservationThreadLocalAccessor";
|
"io.micrometer.observation.contextpropagation.ObservationThreadLocalAccessor";
|
||||||
|
|
||||||
|
@Nullable
|
||||||
private static final String ERROR_MESSAGE;
|
private static final String ERROR_MESSAGE;
|
||||||
|
|
||||||
static {
|
static {
|
||||||
|
|
|
@ -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.
|
||||||
|
@ -143,7 +143,7 @@ class TestPropertySourceAttributes {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addPropertiesAndLocations(List<PropertySourceDescriptor> descriptors, String[] properties,
|
private void addPropertiesAndLocations(List<PropertySourceDescriptor> descriptors, String[] properties,
|
||||||
Class<?> declaringClass, String encoding, boolean prepend) {
|
Class<?> declaringClass, @Nullable String encoding, boolean prepend) {
|
||||||
|
|
||||||
if (hasNoLocations(descriptors) && ObjectUtils.isEmpty(properties)) {
|
if (hasNoLocations(descriptors) && ObjectUtils.isEmpty(properties)) {
|
||||||
String defaultPropertiesFile = detectDefaultPropertiesFile(declaringClass);
|
String defaultPropertiesFile = detectDefaultPropertiesFile(declaringClass);
|
||||||
|
|
|
@ -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.
|
||||||
|
@ -24,9 +24,11 @@ import io.micrometer.common.KeyValues;
|
||||||
|
|
||||||
import org.springframework.http.HttpStatus;
|
import org.springframework.http.HttpStatus;
|
||||||
import org.springframework.http.HttpStatusCode;
|
import org.springframework.http.HttpStatusCode;
|
||||||
|
import org.springframework.http.client.ClientHttpRequest;
|
||||||
import org.springframework.http.client.ClientHttpResponse;
|
import org.springframework.http.client.ClientHttpResponse;
|
||||||
import org.springframework.http.client.observation.ClientHttpObservationDocumentation.HighCardinalityKeyNames;
|
import org.springframework.http.client.observation.ClientHttpObservationDocumentation.HighCardinalityKeyNames;
|
||||||
import org.springframework.http.client.observation.ClientHttpObservationDocumentation.LowCardinalityKeyNames;
|
import org.springframework.http.client.observation.ClientHttpObservationDocumentation.LowCardinalityKeyNames;
|
||||||
|
import org.springframework.lang.Nullable;
|
||||||
import org.springframework.util.StringUtils;
|
import org.springframework.util.StringUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -84,8 +86,10 @@ public class DefaultClientRequestObservationConvention implements ClientRequestO
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@Nullable
|
||||||
public String getContextualName(ClientRequestObservationContext context) {
|
public String getContextualName(ClientRequestObservationContext context) {
|
||||||
return "http " + context.getCarrier().getMethod().name().toLowerCase();
|
ClientHttpRequest request = context.getCarrier();
|
||||||
|
return (request != null ? "http " + request.getMethod().name().toLowerCase() : null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -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.
|
||||||
|
@ -126,9 +126,9 @@ class ReactorNetty2ClientHttpResponse implements ClientHttpResponse {
|
||||||
.flatMap(Collection::stream)
|
.flatMap(Collection::stream)
|
||||||
.forEach(cookie -> result.add(cookie.name().toString(),
|
.forEach(cookie -> result.add(cookie.name().toString(),
|
||||||
ResponseCookie.fromClientResponse(cookie.name().toString(), cookie.value().toString())
|
ResponseCookie.fromClientResponse(cookie.name().toString(), cookie.value().toString())
|
||||||
.domain(cookie.domain() != null ? cookie.domain().toString() : null)
|
.domain(toString(cookie.domain()))
|
||||||
.path(cookie.path() != null ? cookie.path().toString() : null)
|
.path(toString(cookie.path()))
|
||||||
.maxAge(cookie.maxAge() != null ? cookie.maxAge() : -1L)
|
.maxAge(toLong(cookie.maxAge()))
|
||||||
.secure(cookie.isSecure())
|
.secure(cookie.isSecure())
|
||||||
.httpOnly(cookie.isHttpOnly())
|
.httpOnly(cookie.isHttpOnly())
|
||||||
.sameSite(getSameSite(cookie))
|
.sameSite(getSameSite(cookie))
|
||||||
|
@ -136,6 +136,15 @@ class ReactorNetty2ClientHttpResponse implements ClientHttpResponse {
|
||||||
return CollectionUtils.unmodifiableMultiValueMap(result);
|
return CollectionUtils.unmodifiableMultiValueMap(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private static String toString(@Nullable CharSequence value) {
|
||||||
|
return (value != null ? value.toString() : null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static long toLong(@Nullable Long value) {
|
||||||
|
return (value != null ? value : -1);
|
||||||
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
private static String getSameSite(HttpSetCookie cookie) {
|
private static String getSameSite(HttpSetCookie cookie) {
|
||||||
if (cookie instanceof DefaultHttpSetCookie defaultCookie && defaultCookie.sameSite() != null) {
|
if (cookie instanceof DefaultHttpSetCookie defaultCookie && defaultCookie.sameSite() != null) {
|
||||||
|
|
|
@ -301,9 +301,10 @@ public class ChannelSendOperator<T> extends Mono<Void> implements Scannable {
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean emitCachedSignals() {
|
private boolean emitCachedSignals() {
|
||||||
if (this.error != null) {
|
Throwable error = this.error;
|
||||||
|
if (error != null) {
|
||||||
try {
|
try {
|
||||||
requiredWriteSubscriber().onError(this.error);
|
requiredWriteSubscriber().onError(error);
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
releaseCachedItem();
|
releaseCachedItem();
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2022 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.
|
||||||
|
@ -205,32 +205,32 @@ public class ServletWebRequest extends ServletRequestAttributes implements Nativ
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean checkNotModified(@Nullable String eTag, long lastModifiedTimestamp) {
|
public boolean checkNotModified(@Nullable String etag, long lastModifiedTimestamp) {
|
||||||
HttpServletResponse response = getResponse();
|
HttpServletResponse response = getResponse();
|
||||||
if (this.notModified || (response != null && HttpStatus.OK.value() != response.getStatus())) {
|
if (this.notModified || (response != null && HttpStatus.OK.value() != response.getStatus())) {
|
||||||
return this.notModified;
|
return this.notModified;
|
||||||
}
|
}
|
||||||
// Evaluate conditions in order of precedence.
|
// Evaluate conditions in order of precedence.
|
||||||
// See https://datatracker.ietf.org/doc/html/rfc9110#section-13.2.2
|
// See https://datatracker.ietf.org/doc/html/rfc9110#section-13.2.2
|
||||||
if (validateIfMatch(eTag)) {
|
if (validateIfMatch(etag)) {
|
||||||
updateResponseStateChanging(eTag, lastModifiedTimestamp);
|
updateResponseStateChanging(etag, lastModifiedTimestamp);
|
||||||
return this.notModified;
|
return this.notModified;
|
||||||
}
|
}
|
||||||
// 2) If-Unmodified-Since
|
// 2) If-Unmodified-Since
|
||||||
else if (validateIfUnmodifiedSince(lastModifiedTimestamp)) {
|
else if (validateIfUnmodifiedSince(lastModifiedTimestamp)) {
|
||||||
updateResponseStateChanging(eTag, lastModifiedTimestamp);
|
updateResponseStateChanging(etag, lastModifiedTimestamp);
|
||||||
return this.notModified;
|
return this.notModified;
|
||||||
}
|
}
|
||||||
// 3) If-None-Match
|
// 3) If-None-Match
|
||||||
if (!validateIfNoneMatch(eTag)) {
|
if (!validateIfNoneMatch(etag)) {
|
||||||
// 4) If-Modified-Since
|
// 4) If-Modified-Since
|
||||||
validateIfModifiedSince(lastModifiedTimestamp);
|
validateIfModifiedSince(lastModifiedTimestamp);
|
||||||
}
|
}
|
||||||
updateResponseIdempotent(eTag, lastModifiedTimestamp);
|
updateResponseIdempotent(etag, lastModifiedTimestamp);
|
||||||
return this.notModified;
|
return this.notModified;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean validateIfMatch(@Nullable String eTag) {
|
private boolean validateIfMatch(@Nullable String etag) {
|
||||||
if (SAFE_METHODS.contains(getRequest().getMethod())) {
|
if (SAFE_METHODS.contains(getRequest().getMethod())) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -238,37 +238,37 @@ public class ServletWebRequest extends ServletRequestAttributes implements Nativ
|
||||||
if (!ifMatchHeaders.hasMoreElements()) {
|
if (!ifMatchHeaders.hasMoreElements()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
this.notModified = matchRequestedETags(ifMatchHeaders, eTag, false);
|
this.notModified = matchRequestedETags(ifMatchHeaders, etag, false);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean validateIfNoneMatch(@Nullable String eTag) {
|
private boolean validateIfNoneMatch(@Nullable String etag) {
|
||||||
Enumeration<String> ifNoneMatchHeaders = getRequest().getHeaders(HttpHeaders.IF_NONE_MATCH);
|
Enumeration<String> ifNoneMatchHeaders = getRequest().getHeaders(HttpHeaders.IF_NONE_MATCH);
|
||||||
if (!ifNoneMatchHeaders.hasMoreElements()) {
|
if (!ifNoneMatchHeaders.hasMoreElements()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
this.notModified = !matchRequestedETags(ifNoneMatchHeaders, eTag, true);
|
this.notModified = !matchRequestedETags(ifNoneMatchHeaders, etag, true);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean matchRequestedETags(Enumeration<String> requestedETags, @Nullable String eTag, boolean weakCompare) {
|
private boolean matchRequestedETags(Enumeration<String> requestedETags, @Nullable String etag, boolean weakCompare) {
|
||||||
eTag = padEtagIfNecessary(eTag);
|
etag = padEtagIfNecessary(etag);
|
||||||
while (requestedETags.hasMoreElements()) {
|
while (requestedETags.hasMoreElements()) {
|
||||||
// Compare weak/strong ETags as per https://datatracker.ietf.org/doc/html/rfc9110#section-8.8.3
|
// Compare weak/strong ETags as per https://datatracker.ietf.org/doc/html/rfc9110#section-8.8.3
|
||||||
Matcher eTagMatcher = ETAG_HEADER_VALUE_PATTERN.matcher(requestedETags.nextElement());
|
Matcher etagMatcher = ETAG_HEADER_VALUE_PATTERN.matcher(requestedETags.nextElement());
|
||||||
while (eTagMatcher.find()) {
|
while (etagMatcher.find()) {
|
||||||
// only consider "lost updates" checks for unsafe HTTP methods
|
// only consider "lost updates" checks for unsafe HTTP methods
|
||||||
if ("*".equals(eTagMatcher.group()) && StringUtils.hasLength(eTag)
|
if ("*".equals(etagMatcher.group()) && StringUtils.hasLength(etag)
|
||||||
&& !SAFE_METHODS.contains(getRequest().getMethod())) {
|
&& !SAFE_METHODS.contains(getRequest().getMethod())) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (weakCompare) {
|
if (weakCompare) {
|
||||||
if (eTagWeakMatch(eTag, eTagMatcher.group(1))) {
|
if (etagWeakMatch(etag, etagMatcher.group(1))) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (eTagStrongMatch(eTag, eTagMatcher.group(1))) {
|
if (etagStrongMatch(etag, etagMatcher.group(1))) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -288,14 +288,14 @@ public class ServletWebRequest extends ServletRequestAttributes implements Nativ
|
||||||
return "\"" + etag + "\"";
|
return "\"" + etag + "\"";
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean eTagStrongMatch(@Nullable String first, @Nullable String second) {
|
private boolean etagStrongMatch(@Nullable String first, @Nullable String second) {
|
||||||
if (!StringUtils.hasLength(first) || first.startsWith("W/")) {
|
if (!StringUtils.hasLength(first) || first.startsWith("W/")) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return first.equals(second);
|
return first.equals(second);
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean eTagWeakMatch(@Nullable String first, @Nullable String second) {
|
private boolean etagWeakMatch(@Nullable String first, @Nullable String second) {
|
||||||
if (!StringUtils.hasLength(first) || !StringUtils.hasLength(second)) {
|
if (!StringUtils.hasLength(first) || !StringUtils.hasLength(second)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -308,12 +308,12 @@ public class ServletWebRequest extends ServletRequestAttributes implements Nativ
|
||||||
return first.equals(second);
|
return first.equals(second);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateResponseStateChanging(@Nullable String eTag, long lastModifiedTimestamp) {
|
private void updateResponseStateChanging(@Nullable String etag, long lastModifiedTimestamp) {
|
||||||
if (this.notModified && getResponse() != null) {
|
if (this.notModified && getResponse() != null) {
|
||||||
getResponse().setStatus(HttpStatus.PRECONDITION_FAILED.value());
|
getResponse().setStatus(HttpStatus.PRECONDITION_FAILED.value());
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
addCachingResponseHeaders(eTag, lastModifiedTimestamp);
|
addCachingResponseHeaders(etag, lastModifiedTimestamp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -340,24 +340,24 @@ public class ServletWebRequest extends ServletRequestAttributes implements Nativ
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateResponseIdempotent(@Nullable String eTag, long lastModifiedTimestamp) {
|
private void updateResponseIdempotent(@Nullable String etag, long lastModifiedTimestamp) {
|
||||||
if (getResponse() != null) {
|
if (getResponse() != null) {
|
||||||
boolean isHttpGetOrHead = SAFE_METHODS.contains(getRequest().getMethod());
|
boolean isHttpGetOrHead = SAFE_METHODS.contains(getRequest().getMethod());
|
||||||
if (this.notModified) {
|
if (this.notModified) {
|
||||||
getResponse().setStatus(isHttpGetOrHead ?
|
getResponse().setStatus(isHttpGetOrHead ?
|
||||||
HttpStatus.NOT_MODIFIED.value() : HttpStatus.PRECONDITION_FAILED.value());
|
HttpStatus.NOT_MODIFIED.value() : HttpStatus.PRECONDITION_FAILED.value());
|
||||||
}
|
}
|
||||||
addCachingResponseHeaders(eTag, lastModifiedTimestamp);
|
addCachingResponseHeaders(etag, lastModifiedTimestamp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addCachingResponseHeaders(@Nullable String eTag, long lastModifiedTimestamp) {
|
private void addCachingResponseHeaders(@Nullable String etag, long lastModifiedTimestamp) {
|
||||||
if (SAFE_METHODS.contains(getRequest().getMethod())) {
|
if (getResponse() != null && SAFE_METHODS.contains(getRequest().getMethod())) {
|
||||||
if (lastModifiedTimestamp > 0 && parseDateValue(getResponse().getHeader(HttpHeaders.LAST_MODIFIED)) == -1) {
|
if (lastModifiedTimestamp > 0 && parseDateValue(getResponse().getHeader(HttpHeaders.LAST_MODIFIED)) == -1) {
|
||||||
getResponse().setDateHeader(HttpHeaders.LAST_MODIFIED, lastModifiedTimestamp);
|
getResponse().setDateHeader(HttpHeaders.LAST_MODIFIED, lastModifiedTimestamp);
|
||||||
}
|
}
|
||||||
if (StringUtils.hasLength(eTag) && getResponse().getHeader(HttpHeaders.ETAG) == null) {
|
if (StringUtils.hasLength(etag) && getResponse().getHeader(HttpHeaders.ETAG) == null) {
|
||||||
getResponse().setHeader(HttpHeaders.ETAG, padEtagIfNecessary(eTag));
|
getResponse().setHeader(HttpHeaders.ETAG, padEtagIfNecessary(etag));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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.
|
||||||
|
@ -68,6 +68,7 @@ class CallableInterceptorChain {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
public Object applyPostProcess(NativeWebRequest request, Callable<?> task, @Nullable Object concurrentResult) {
|
public Object applyPostProcess(NativeWebRequest request, Callable<?> task, @Nullable Object concurrentResult) {
|
||||||
Throwable exceptionResult = null;
|
Throwable exceptionResult = null;
|
||||||
for (int i = this.preProcessIndex; i >= 0; i--) {
|
for (int i = this.preProcessIndex; i >= 0; i--) {
|
||||||
|
@ -86,7 +87,7 @@ class CallableInterceptorChain {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return (exceptionResult != null) ? exceptionResult : concurrentResult;
|
return (exceptionResult != null ? exceptionResult : concurrentResult);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Object triggerAfterTimeout(NativeWebRequest request, Callable<?> task) {
|
public Object triggerAfterTimeout(NativeWebRequest request, Callable<?> task) {
|
||||||
|
|
|
@ -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.
|
||||||
|
@ -96,7 +96,7 @@ public class DeferredResult<T> {
|
||||||
* timeout depends on the default of the underlying server.
|
* timeout depends on the default of the underlying server.
|
||||||
* @param timeoutValue timeout value in milliseconds
|
* @param timeoutValue timeout value in milliseconds
|
||||||
*/
|
*/
|
||||||
public DeferredResult(Long timeoutValue) {
|
public DeferredResult(@Nullable Long timeoutValue) {
|
||||||
this(timeoutValue, () -> RESULT_NONE);
|
this(timeoutValue, () -> RESULT_NONE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -239,11 +239,11 @@ public class DeferredResult<T> {
|
||||||
* {@code false} if the result was already set or the async request expired
|
* {@code false} if the result was already set or the async request expired
|
||||||
* @see #isSetOrExpired()
|
* @see #isSetOrExpired()
|
||||||
*/
|
*/
|
||||||
public boolean setResult(T result) {
|
public boolean setResult(@Nullable T result) {
|
||||||
return setResultInternal(result);
|
return setResultInternal(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean setResultInternal(Object result) {
|
private boolean setResultInternal(@Nullable Object result) {
|
||||||
// Immediate expiration check outside of the result lock
|
// Immediate expiration check outside of the result lock
|
||||||
if (isSetOrExpired()) {
|
if (isSetOrExpired()) {
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -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.
|
||||||
|
@ -37,7 +37,6 @@ import org.springframework.web.server.WebFilter;
|
||||||
import org.springframework.web.server.WebFilterChain;
|
import org.springframework.web.server.WebFilterChain;
|
||||||
import org.springframework.web.server.adapter.WebHttpHandlerBuilder;
|
import org.springframework.web.server.adapter.WebHttpHandlerBuilder;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@link org.springframework.web.server.WebFilter} that creates {@link Observation observations}
|
* {@link org.springframework.web.server.WebFilter} that creates {@link Observation observations}
|
||||||
* for HTTP exchanges. This collects information about the execution time and
|
* for HTTP exchanges. This collects information about the execution time and
|
||||||
|
@ -160,6 +159,7 @@ public class ServerHttpObservationFilter implements WebFilter {
|
||||||
|
|
||||||
private void doOnTerminate(ServerRequestObservationContext context) {
|
private void doOnTerminate(ServerRequestObservationContext context) {
|
||||||
ServerHttpResponse response = context.getResponse();
|
ServerHttpResponse response = context.getResponse();
|
||||||
|
if (response != null) {
|
||||||
if (response.isCommitted()) {
|
if (response.isCommitted()) {
|
||||||
this.observation.stop();
|
this.observation.stop();
|
||||||
}
|
}
|
||||||
|
@ -171,5 +171,6 @@ public class ServerHttpObservationFilter implements WebFilter {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
|
|
||||||
package org.springframework.web.method.annotation;
|
package org.springframework.web.method.annotation;
|
||||||
|
|
||||||
|
import java.lang.reflect.Constructor;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
@ -284,7 +285,10 @@ public abstract class AbstractNamedValueMethodArgumentResolver implements Handle
|
||||||
WebDataBinder binder = binderFactory.createBinder(webRequest, null, namedValueInfo.name);
|
WebDataBinder binder = binderFactory.createBinder(webRequest, null, namedValueInfo.name);
|
||||||
Class<?> parameterType = parameter.getParameterType();
|
Class<?> parameterType = parameter.getParameterType();
|
||||||
if (KotlinDetector.isKotlinPresent() && KotlinDetector.isInlineClass(parameterType)) {
|
if (KotlinDetector.isKotlinPresent() && KotlinDetector.isInlineClass(parameterType)) {
|
||||||
parameterType = BeanUtils.findPrimaryConstructor(parameterType).getParameterTypes()[0];
|
Constructor<?> ctor = BeanUtils.findPrimaryConstructor(parameterType);
|
||||||
|
if (ctor != null) {
|
||||||
|
parameterType = ctor.getParameterTypes()[0];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
arg = binder.convertIfNecessary(arg, parameterType, parameter);
|
arg = binder.convertIfNecessary(arg, parameterType, parameter);
|
||||||
|
|
|
@ -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.
|
||||||
|
@ -414,6 +414,7 @@ public class HttpWebHandlerAdapter extends WebHandlerDecorator implements HttpHa
|
||||||
|
|
||||||
private void doOnTerminate(ServerRequestObservationContext context) {
|
private void doOnTerminate(ServerRequestObservationContext context) {
|
||||||
ServerHttpResponse response = context.getResponse();
|
ServerHttpResponse response = context.getResponse();
|
||||||
|
if (response != null) {
|
||||||
if (response.isCommitted()) {
|
if (response.isCommitted()) {
|
||||||
this.observation.stop();
|
this.observation.stop();
|
||||||
}
|
}
|
||||||
|
@ -425,5 +426,6 @@ public class HttpWebHandlerAdapter extends WebHandlerDecorator implements HttpHa
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2022 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.
|
||||||
|
@ -134,7 +134,7 @@ class RegexPathElement extends PathElement {
|
||||||
if (matches) {
|
if (matches) {
|
||||||
if (isNoMorePattern()) {
|
if (isNoMorePattern()) {
|
||||||
if (matchingContext.determineRemainingPath &&
|
if (matchingContext.determineRemainingPath &&
|
||||||
(this.variableNames.isEmpty() || textToMatch.length() > 0)) {
|
(this.variableNames.isEmpty() || !textToMatch.isEmpty())) {
|
||||||
matchingContext.remainingPathIndex = pathIndex + 1;
|
matchingContext.remainingPathIndex = pathIndex + 1;
|
||||||
matches = true;
|
matches = true;
|
||||||
}
|
}
|
||||||
|
@ -142,9 +142,9 @@ class RegexPathElement extends PathElement {
|
||||||
// No more pattern, is there more data?
|
// No more pattern, is there more data?
|
||||||
// If pattern is capturing variables there must be some actual data to bind to them
|
// If pattern is capturing variables there must be some actual data to bind to them
|
||||||
matches = (pathIndex + 1 >= matchingContext.pathLength) &&
|
matches = (pathIndex + 1 >= matchingContext.pathLength) &&
|
||||||
(this.variableNames.isEmpty() || textToMatch.length() > 0);
|
(this.variableNames.isEmpty() || !textToMatch.isEmpty());
|
||||||
if (!matches && matchingContext.isMatchOptionalTrailingSeparator()) {
|
if (!matches && matchingContext.isMatchOptionalTrailingSeparator()) {
|
||||||
matches = (this.variableNames.isEmpty() || textToMatch.length() > 0) &&
|
matches = (this.variableNames.isEmpty() || !textToMatch.isEmpty()) &&
|
||||||
(pathIndex + 2 >= matchingContext.pathLength) &&
|
(pathIndex + 2 >= matchingContext.pathLength) &&
|
||||||
matchingContext.isSeparator(pathIndex + 1);
|
matchingContext.isSeparator(pathIndex + 1);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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.
|
||||||
|
@ -24,6 +24,7 @@ import io.micrometer.common.KeyValues;
|
||||||
|
|
||||||
import org.springframework.http.HttpStatus;
|
import org.springframework.http.HttpStatus;
|
||||||
import org.springframework.http.HttpStatusCode;
|
import org.springframework.http.HttpStatusCode;
|
||||||
|
import org.springframework.lang.Nullable;
|
||||||
import org.springframework.util.StringUtils;
|
import org.springframework.util.StringUtils;
|
||||||
import org.springframework.web.reactive.function.client.ClientHttpObservationDocumentation.HighCardinalityKeyNames;
|
import org.springframework.web.reactive.function.client.ClientHttpObservationDocumentation.HighCardinalityKeyNames;
|
||||||
import org.springframework.web.reactive.function.client.ClientHttpObservationDocumentation.LowCardinalityKeyNames;
|
import org.springframework.web.reactive.function.client.ClientHttpObservationDocumentation.LowCardinalityKeyNames;
|
||||||
|
@ -88,8 +89,10 @@ public class DefaultClientRequestObservationConvention implements ClientRequestO
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@Nullable
|
||||||
public String getContextualName(ClientRequestObservationContext context) {
|
public String getContextualName(ClientRequestObservationContext context) {
|
||||||
return "http " + context.getRequest().method().name().toLowerCase();
|
ClientRequest request = context.getRequest();
|
||||||
|
return (request != null ? "http " + request.method().name().toLowerCase() : null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -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.
|
||||||
|
@ -94,7 +94,7 @@ public class ResourceUrlProvider implements ApplicationListener<ContextRefreshed
|
||||||
@Override
|
@Override
|
||||||
public void onApplicationEvent(ContextRefreshedEvent event) {
|
public void onApplicationEvent(ContextRefreshedEvent event) {
|
||||||
if (this.applicationContext == event.getApplicationContext() && this.handlerMap.isEmpty()) {
|
if (this.applicationContext == event.getApplicationContext() && this.handlerMap.isEmpty()) {
|
||||||
detectResourceHandlers(this.applicationContext);
|
detectResourceHandlers(event.getApplicationContext());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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.
|
||||||
|
@ -75,14 +75,14 @@ public final class ConsumesRequestCondition extends AbstractRequestCondition<Con
|
||||||
* @param consumes as described in {@link RequestMapping#consumes()}
|
* @param consumes as described in {@link RequestMapping#consumes()}
|
||||||
* @param headers as described in {@link RequestMapping#headers()}
|
* @param headers as described in {@link RequestMapping#headers()}
|
||||||
*/
|
*/
|
||||||
public ConsumesRequestCondition(String[] consumes, String[] headers) {
|
public ConsumesRequestCondition(@Nullable String[] consumes, @Nullable String[] headers) {
|
||||||
this.expressions = parseExpressions(consumes, headers);
|
this.expressions = parseExpressions(consumes, headers);
|
||||||
if (this.expressions.size() > 1) {
|
if (this.expressions.size() > 1) {
|
||||||
Collections.sort(this.expressions);
|
Collections.sort(this.expressions);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static List<ConsumeMediaTypeExpression> parseExpressions(String[] consumes, String[] headers) {
|
private static List<ConsumeMediaTypeExpression> parseExpressions(@Nullable String[] consumes, @Nullable String[] headers) {
|
||||||
Set<ConsumeMediaTypeExpression> result = null;
|
Set<ConsumeMediaTypeExpression> result = null;
|
||||||
if (!ObjectUtils.isEmpty(headers)) {
|
if (!ObjectUtils.isEmpty(headers)) {
|
||||||
for (String header : headers) {
|
for (String header : headers) {
|
||||||
|
|
|
@ -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.
|
||||||
|
@ -81,7 +81,7 @@ public final class ProducesRequestCondition extends AbstractRequestCondition<Pro
|
||||||
* @param produces expressions with syntax defined by {@link RequestMapping#produces()}
|
* @param produces expressions with syntax defined by {@link RequestMapping#produces()}
|
||||||
* @param headers expressions with syntax defined by {@link RequestMapping#headers()}
|
* @param headers expressions with syntax defined by {@link RequestMapping#headers()}
|
||||||
*/
|
*/
|
||||||
public ProducesRequestCondition(String[] produces, String[] headers) {
|
public ProducesRequestCondition(@Nullable String[] produces, @Nullable String[] headers) {
|
||||||
this(produces, headers, null);
|
this(produces, headers, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -92,15 +92,17 @@ public final class ProducesRequestCondition extends AbstractRequestCondition<Pro
|
||||||
* @param headers expressions with syntax defined by {@link RequestMapping#headers()}
|
* @param headers expressions with syntax defined by {@link RequestMapping#headers()}
|
||||||
* @param resolver used to determine requested content type
|
* @param resolver used to determine requested content type
|
||||||
*/
|
*/
|
||||||
public ProducesRequestCondition(String[] produces, String[] headers, RequestedContentTypeResolver resolver) {
|
public ProducesRequestCondition(
|
||||||
|
@Nullable String[] produces, @Nullable String[] headers, @Nullable RequestedContentTypeResolver resolver) {
|
||||||
|
|
||||||
this.expressions = parseExpressions(produces, headers);
|
this.expressions = parseExpressions(produces, headers);
|
||||||
if (this.expressions.size() > 1) {
|
if (this.expressions.size() > 1) {
|
||||||
Collections.sort(this.expressions);
|
Collections.sort(this.expressions);
|
||||||
}
|
}
|
||||||
this.contentTypeResolver = resolver != null ? resolver : DEFAULT_CONTENT_TYPE_RESOLVER;
|
this.contentTypeResolver = (resolver != null ? resolver : DEFAULT_CONTENT_TYPE_RESOLVER);
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<ProduceMediaTypeExpression> parseExpressions(String[] produces, String[] headers) {
|
private List<ProduceMediaTypeExpression> parseExpressions(@Nullable String[] produces, @Nullable String[] headers) {
|
||||||
Set<ProduceMediaTypeExpression> result = null;
|
Set<ProduceMediaTypeExpression> result = null;
|
||||||
if (!ObjectUtils.isEmpty(headers)) {
|
if (!ObjectUtils.isEmpty(headers)) {
|
||||||
for (String header : headers) {
|
for (String header : headers) {
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
|
|
||||||
package org.springframework.web.reactive.result.method.annotation;
|
package org.springframework.web.reactive.result.method.annotation;
|
||||||
|
|
||||||
|
import java.lang.reflect.Constructor;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
@ -200,7 +201,10 @@ public abstract class AbstractNamedValueArgumentResolver extends HandlerMethodAr
|
||||||
WebDataBinder binder = bindingContext.createDataBinder(exchange, namedValueInfo.name);
|
WebDataBinder binder = bindingContext.createDataBinder(exchange, namedValueInfo.name);
|
||||||
Class<?> parameterType = parameter.getParameterType();
|
Class<?> parameterType = parameter.getParameterType();
|
||||||
if (KotlinDetector.isKotlinPresent() && KotlinDetector.isInlineClass(parameterType)) {
|
if (KotlinDetector.isKotlinPresent() && KotlinDetector.isInlineClass(parameterType)) {
|
||||||
parameterType = BeanUtils.findPrimaryConstructor(parameterType).getParameterTypes()[0];
|
Constructor<?> ctor = BeanUtils.findPrimaryConstructor(parameterType);
|
||||||
|
if (ctor != null) {
|
||||||
|
parameterType = ctor.getParameterTypes()[0];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
value = binder.convertIfNecessary(value, parameterType, parameter);
|
value = binder.convertIfNecessary(value, parameterType, parameter);
|
||||||
|
|
|
@ -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.
|
||||||
|
@ -32,7 +32,6 @@ import org.springframework.core.ReactiveAdapter;
|
||||||
import org.springframework.core.ReactiveAdapterRegistry;
|
import org.springframework.core.ReactiveAdapterRegistry;
|
||||||
import org.springframework.core.ResolvableType;
|
import org.springframework.core.ResolvableType;
|
||||||
import org.springframework.core.annotation.AnnotatedElementUtils;
|
import org.springframework.core.annotation.AnnotatedElementUtils;
|
||||||
import org.springframework.lang.Nullable;
|
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
import org.springframework.util.StringUtils;
|
import org.springframework.util.StringUtils;
|
||||||
import org.springframework.web.bind.annotation.ModelAttribute;
|
import org.springframework.web.bind.annotation.ModelAttribute;
|
||||||
|
@ -74,7 +73,6 @@ class ModelInitializer {
|
||||||
* @param exchange the current exchange
|
* @param exchange the current exchange
|
||||||
* @return a {@code Mono} for when the model is populated.
|
* @return a {@code Mono} for when the model is populated.
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("Convert2MethodRef")
|
|
||||||
public Mono<Void> initModel(HandlerMethod handlerMethod, InitBinderBindingContext bindingContext,
|
public Mono<Void> initModel(HandlerMethod handlerMethod, InitBinderBindingContext bindingContext,
|
||||||
ServerWebExchange exchange) {
|
ServerWebExchange exchange) {
|
||||||
|
|
||||||
|
@ -124,7 +122,7 @@ class ModelInitializer {
|
||||||
ResolvableType type = handlerResult.getReturnType();
|
ResolvableType type = handlerResult.getReturnType();
|
||||||
MethodParameter typeSource = handlerResult.getReturnTypeSource();
|
MethodParameter typeSource = handlerResult.getReturnTypeSource();
|
||||||
ReactiveAdapter adapter = this.adapterRegistry.getAdapter(type.resolve(), value);
|
ReactiveAdapter adapter = this.adapterRegistry.getAdapter(type.resolve(), value);
|
||||||
if (isAsyncVoidType(type, typeSource, adapter)) {
|
if (adapter != null && isAsyncVoidType(type, typeSource, adapter)) {
|
||||||
return Mono.from(adapter.toPublisher(value));
|
return Mono.from(adapter.toPublisher(value));
|
||||||
}
|
}
|
||||||
String name = getAttributeName(typeSource);
|
String name = getAttributeName(typeSource);
|
||||||
|
@ -134,10 +132,10 @@ class ModelInitializer {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private boolean isAsyncVoidType(ResolvableType type, MethodParameter typeSource, @Nullable ReactiveAdapter adapter) {
|
private boolean isAsyncVoidType(ResolvableType type, MethodParameter typeSource, ReactiveAdapter adapter) {
|
||||||
Method method = typeSource.getMethod();
|
Method method = typeSource.getMethod();
|
||||||
return (adapter != null && (adapter.isNoValue() || type.resolveGeneric() == Void.class)) ||
|
return (adapter.isNoValue() || type.resolveGeneric() == Void.class || (method != null &&
|
||||||
(method != null && KotlinDetector.isSuspendingFunction(method) && typeSource.getParameterType() == void.class);
|
KotlinDetector.isSuspendingFunction(method) && typeSource.getParameterType() == void.class));
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getAttributeName(MethodParameter param) {
|
private String getAttributeName(MethodParameter param) {
|
||||||
|
|
|
@ -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.
|
||||||
|
@ -94,7 +94,6 @@ public class ResponseEntityResultHandler extends AbstractMessageWriterResultHand
|
||||||
isSupportedType(result.getReturnType().getGeneric().toClass());
|
isSupportedType(result.getReturnType().getGeneric().toClass());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
|
||||||
private static Class<?> resolveReturnValueType(HandlerResult result) {
|
private static Class<?> resolveReturnValueType(HandlerResult result) {
|
||||||
Class<?> valueType = result.getReturnType().toClass();
|
Class<?> valueType = result.getReturnType().toClass();
|
||||||
Object value = result.getReturnValue();
|
Object value = result.getReturnValue();
|
||||||
|
|
|
@ -76,14 +76,14 @@ public final class ConsumesRequestCondition extends AbstractRequestCondition<Con
|
||||||
* @param consumes as described in {@link RequestMapping#consumes()}
|
* @param consumes as described in {@link RequestMapping#consumes()}
|
||||||
* @param headers as described in {@link RequestMapping#headers()}
|
* @param headers as described in {@link RequestMapping#headers()}
|
||||||
*/
|
*/
|
||||||
public ConsumesRequestCondition(String[] consumes, @Nullable String[] headers) {
|
public ConsumesRequestCondition(@Nullable String[] consumes, @Nullable String[] headers) {
|
||||||
this.expressions = parseExpressions(consumes, headers);
|
this.expressions = parseExpressions(consumes, headers);
|
||||||
if (this.expressions.size() > 1) {
|
if (this.expressions.size() > 1) {
|
||||||
Collections.sort(this.expressions);
|
Collections.sort(this.expressions);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static List<ConsumeMediaTypeExpression> parseExpressions(String[] consumes, @Nullable String[] headers) {
|
private static List<ConsumeMediaTypeExpression> parseExpressions(@Nullable String[] consumes, @Nullable String[] headers) {
|
||||||
Set<ConsumeMediaTypeExpression> result = null;
|
Set<ConsumeMediaTypeExpression> result = null;
|
||||||
if (!ObjectUtils.isEmpty(headers)) {
|
if (!ObjectUtils.isEmpty(headers)) {
|
||||||
for (String header : headers) {
|
for (String header : headers) {
|
||||||
|
|
|
@ -83,7 +83,7 @@ public final class ProducesRequestCondition extends AbstractRequestCondition<Pro
|
||||||
* @param produces expressions with syntax defined by {@link RequestMapping#produces()}
|
* @param produces expressions with syntax defined by {@link RequestMapping#produces()}
|
||||||
* @param headers expressions with syntax defined by {@link RequestMapping#headers()}
|
* @param headers expressions with syntax defined by {@link RequestMapping#headers()}
|
||||||
*/
|
*/
|
||||||
public ProducesRequestCondition(String[] produces, @Nullable String[] headers) {
|
public ProducesRequestCondition(@Nullable String[] produces, @Nullable String[] headers) {
|
||||||
this(produces, headers, null);
|
this(produces, headers, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -94,17 +94,17 @@ public final class ProducesRequestCondition extends AbstractRequestCondition<Pro
|
||||||
* @param headers expressions with syntax defined by {@link RequestMapping#headers()}
|
* @param headers expressions with syntax defined by {@link RequestMapping#headers()}
|
||||||
* @param manager used to determine requested media types
|
* @param manager used to determine requested media types
|
||||||
*/
|
*/
|
||||||
public ProducesRequestCondition(String[] produces, @Nullable String[] headers,
|
public ProducesRequestCondition(@Nullable String[] produces, @Nullable String[] headers,
|
||||||
@Nullable ContentNegotiationManager manager) {
|
@Nullable ContentNegotiationManager manager) {
|
||||||
|
|
||||||
this.expressions = parseExpressions(produces, headers);
|
this.expressions = parseExpressions(produces, headers);
|
||||||
if (this.expressions.size() > 1) {
|
if (this.expressions.size() > 1) {
|
||||||
Collections.sort(this.expressions);
|
Collections.sort(this.expressions);
|
||||||
}
|
}
|
||||||
this.contentNegotiationManager = manager != null ? manager : DEFAULT_CONTENT_NEGOTIATION_MANAGER;
|
this.contentNegotiationManager = (manager != null ? manager : DEFAULT_CONTENT_NEGOTIATION_MANAGER);
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<ProduceMediaTypeExpression> parseExpressions(String[] produces, @Nullable String[] headers) {
|
private List<ProduceMediaTypeExpression> parseExpressions(@Nullable String[] produces, @Nullable String[] headers) {
|
||||||
Set<ProduceMediaTypeExpression> result = null;
|
Set<ProduceMediaTypeExpression> result = null;
|
||||||
if (!ObjectUtils.isEmpty(headers)) {
|
if (!ObjectUtils.isEmpty(headers)) {
|
||||||
for (String header : headers) {
|
for (String header : headers) {
|
||||||
|
|
Loading…
Reference in New Issue