mirror of
https://github.com/spring-projects/spring-boot.git
synced 2026-09-17 12:09:16 +00:00
Replace @OptionalParameter with JSpecify's @Nullable
This commit removes OptionalParameter in favor of the nullness support introduced in Spring Framework 7. The parameter of an action can now be flagged as optional using JSpecify's @Nullable, and simplifies the setup for those who are using JSpecify as only a single annotation is required. Closes gh-45390
This commit is contained in:
+2
-14
@@ -109,8 +109,6 @@ public class ConfigurationMetadataAnnotationProcessor extends AbstractProcessor
|
||||
|
||||
static final String READ_OPERATION_ANNOTATION = "org.springframework.boot.actuate.endpoint.annotation.ReadOperation";
|
||||
|
||||
static final String OPTIONAL_PARAMETER_ANNOTATION = "org.springframework.boot.actuate.endpoint.annotation.OptionalParameter";
|
||||
|
||||
static final String NAME_ANNOTATION = "org.springframework.boot.context.properties.bind.Name";
|
||||
|
||||
static final String ENDPOINT_ACCESS_ENUM = "org.springframework.boot.actuate.endpoint.Access";
|
||||
@@ -166,10 +164,6 @@ public class ConfigurationMetadataAnnotationProcessor extends AbstractProcessor
|
||||
return NAME_ANNOTATION;
|
||||
}
|
||||
|
||||
protected String optionalParameterAnnotation() {
|
||||
return OPTIONAL_PARAMETER_ANNOTATION;
|
||||
}
|
||||
|
||||
protected String endpointAccessEnum() {
|
||||
return ENDPOINT_ACCESS_ENUM;
|
||||
}
|
||||
@@ -194,8 +188,7 @@ public class ConfigurationMetadataAnnotationProcessor extends AbstractProcessor
|
||||
this.metadataEnv = new MetadataGenerationEnvironment(env, configurationPropertiesAnnotation(),
|
||||
configurationPropertiesSourceAnnotation(), nestedConfigurationPropertyAnnotation(),
|
||||
deprecatedConfigurationPropertyAnnotation(), constructorBindingAnnotation(), autowiredAnnotation(),
|
||||
defaultValueAnnotation(), endpointAnnotations(), readOperationAnnotation(),
|
||||
optionalParameterAnnotation(), nameAnnotation());
|
||||
defaultValueAnnotation(), endpointAnnotations(), readOperationAnnotation(), nameAnnotation());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -383,18 +376,13 @@ public class ConfigurationMetadataAnnotationProcessor extends AbstractProcessor
|
||||
|
||||
private boolean hasNoOrOptionalParameters(ExecutableElement method) {
|
||||
for (VariableElement parameter : method.getParameters()) {
|
||||
if (!isOptionalParameter(parameter)) {
|
||||
if (!this.metadataEnv.hasNullableAnnotation(parameter)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean isOptionalParameter(VariableElement parameter) {
|
||||
return this.metadataEnv.hasNullableAnnotation(parameter)
|
||||
|| this.metadataEnv.hasOptionalParameterAnnotation(parameter);
|
||||
}
|
||||
|
||||
private String getPrefix(AnnotationMirror annotation) {
|
||||
String prefix = this.metadataEnv.getAnnotationElementStringValue(annotation, "prefix");
|
||||
if (prefix != null) {
|
||||
|
||||
+1
-8
@@ -98,8 +98,6 @@ class MetadataGenerationEnvironment {
|
||||
|
||||
private final String readOperationAnnotation;
|
||||
|
||||
private final String optionalParameterAnnotation;
|
||||
|
||||
private final String nameAnnotation;
|
||||
|
||||
private final String autowiredAnnotation;
|
||||
@@ -108,7 +106,7 @@ class MetadataGenerationEnvironment {
|
||||
String configurationPropertiesSourceAnnotation, String nestedConfigurationPropertyAnnotation,
|
||||
String deprecatedConfigurationPropertyAnnotation, String constructorBindingAnnotation,
|
||||
String autowiredAnnotation, String defaultValueAnnotation, Set<String> endpointAnnotations,
|
||||
String readOperationAnnotation, String optionalParameterAnnotation, String nameAnnotation) {
|
||||
String readOperationAnnotation, String nameAnnotation) {
|
||||
this.typeUtils = new TypeUtils(environment);
|
||||
this.elements = environment.getElementUtils();
|
||||
this.messager = environment.getMessager();
|
||||
@@ -123,7 +121,6 @@ class MetadataGenerationEnvironment {
|
||||
this.defaultValueAnnotation = defaultValueAnnotation;
|
||||
this.endpointAnnotations = endpointAnnotations;
|
||||
this.readOperationAnnotation = readOperationAnnotation;
|
||||
this.optionalParameterAnnotation = optionalParameterAnnotation;
|
||||
this.nameAnnotation = nameAnnotation;
|
||||
}
|
||||
|
||||
@@ -382,10 +379,6 @@ class MetadataGenerationEnvironment {
|
||||
return getTypeUseAnnotation(element, NULLABLE_ANNOTATION) != null;
|
||||
}
|
||||
|
||||
boolean hasOptionalParameterAnnotation(Element element) {
|
||||
return getAnnotation(element, this.optionalParameterAnnotation) != null;
|
||||
}
|
||||
|
||||
private boolean isElementDeprecated(Element element) {
|
||||
return hasAnnotation(element, "java.lang.Deprecated")
|
||||
|| hasAnnotation(element, this.deprecatedConfigurationPropertyAnnotation);
|
||||
|
||||
+1
-12
@@ -29,7 +29,6 @@ import org.springframework.boot.configurationsample.endpoint.CustomPropertiesEnd
|
||||
import org.springframework.boot.configurationsample.endpoint.EnabledEndpoint;
|
||||
import org.springframework.boot.configurationsample.endpoint.NoAccessEndpoint;
|
||||
import org.springframework.boot.configurationsample.endpoint.NullableParameterEndpoint;
|
||||
import org.springframework.boot.configurationsample.endpoint.OptionalParameterEndpoint;
|
||||
import org.springframework.boot.configurationsample.endpoint.ReadOnlyAccessEndpoint;
|
||||
import org.springframework.boot.configurationsample.endpoint.SimpleEndpoint;
|
||||
import org.springframework.boot.configurationsample.endpoint.SimpleEndpoint2;
|
||||
@@ -153,7 +152,7 @@ class EndpointMetadataGenerationTests extends AbstractMetadataGenerationTests {
|
||||
assertThat(metadata).has(access("incremental", Access.UNRESTRICTED));
|
||||
assertThat(metadata).has(cacheTtl("incremental"));
|
||||
assertThat(metadata.getItems()).hasSize(3);
|
||||
project.replaceText(IncrementalEndpoint.class, "@OptionalParameter String param", "String param");
|
||||
project.replaceText(IncrementalEndpoint.class, "@Nullable String param", "String param");
|
||||
metadata = project.compile();
|
||||
assertThat(metadata)
|
||||
.has(Metadata.withGroup("management.endpoint.incremental").fromSource(IncrementalEndpoint.class));
|
||||
@@ -205,16 +204,6 @@ class EndpointMetadataGenerationTests extends AbstractMetadataGenerationTests {
|
||||
assertThat(metadata.getItems()).hasSize(3);
|
||||
}
|
||||
|
||||
@Test
|
||||
void endpointWithOptionalParameter() {
|
||||
ConfigurationMetadata metadata = compile(OptionalParameterEndpoint.class);
|
||||
assertThat(metadata)
|
||||
.has(Metadata.withGroup("management.endpoint.optional").fromSource(OptionalParameterEndpoint.class));
|
||||
assertThat(metadata).has(access("optional", Access.UNRESTRICTED));
|
||||
assertThat(metadata).has(cacheTtl("optional"));
|
||||
assertThat(metadata.getItems()).hasSize(3);
|
||||
}
|
||||
|
||||
private Metadata.MetadataItemCondition access(String endpointId, Access defaultValue) {
|
||||
return defaultAccess(endpointId, endpointId, defaultValue);
|
||||
}
|
||||
|
||||
-1
@@ -49,7 +49,6 @@ class MetadataGenerationEnvironmentFactory implements Function<ProcessingEnviron
|
||||
TestConfigurationMetadataAnnotationProcessor.AUTOWIRED_ANNOTATION,
|
||||
TestConfigurationMetadataAnnotationProcessor.DEFAULT_VALUE_ANNOTATION, endpointAnnotations,
|
||||
TestConfigurationMetadataAnnotationProcessor.READ_OPERATION_ANNOTATION,
|
||||
TestConfigurationMetadataAnnotationProcessor.OPTIONAL_PARAMETER_ANNOTATION,
|
||||
TestConfigurationMetadataAnnotationProcessor.NAME_ANNOTATION);
|
||||
}
|
||||
|
||||
|
||||
-7
@@ -75,8 +75,6 @@ public class TestConfigurationMetadataAnnotationProcessor extends ConfigurationM
|
||||
|
||||
public static final String READ_OPERATION_ANNOTATION = "org.springframework.boot.configurationsample.ReadOperation";
|
||||
|
||||
public static final String OPTIONAL_PARAMETER_ANNOTATION = "org.springframework.boot.configurationsample.OptionalParameter";
|
||||
|
||||
public static final String NAME_ANNOTATION = "org.springframework.boot.configurationsample.Name";
|
||||
|
||||
public static final String ENDPOINT_ACCESS_ENUM = "org.springframework.boot.configurationsample.Access";
|
||||
@@ -130,11 +128,6 @@ public class TestConfigurationMetadataAnnotationProcessor extends ConfigurationM
|
||||
return READ_OPERATION_ANNOTATION;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String optionalParameterAnnotation() {
|
||||
return OPTIONAL_PARAMETER_ANNOTATION;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String nameAnnotation() {
|
||||
return NAME_ANNOTATION;
|
||||
|
||||
-36
@@ -1,36 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-present the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.configurationsample;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Alternative to Spring Boot's {@code @OptionalParameter} for testing (removes the need
|
||||
* for a dependency on the real annotation).
|
||||
*
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
@Target({ ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
public @interface OptionalParameter {
|
||||
|
||||
}
|
||||
-36
@@ -1,36 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-present the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.configurationsample.endpoint;
|
||||
|
||||
import org.springframework.boot.configurationsample.Endpoint;
|
||||
import org.springframework.boot.configurationsample.OptionalParameter;
|
||||
import org.springframework.boot.configurationsample.ReadOperation;
|
||||
|
||||
/**
|
||||
* An endpoint that uses {@code OptionalParameter} to signal an optional parameter.
|
||||
*
|
||||
* @author Wonyong Hwang
|
||||
*/
|
||||
@Endpoint(id = "optional")
|
||||
public class OptionalParameterEndpoint {
|
||||
|
||||
@ReadOperation
|
||||
public String invoke(@OptionalParameter String parameter) {
|
||||
return "test with " + parameter;
|
||||
}
|
||||
|
||||
}
|
||||
+3
-2
@@ -16,8 +16,9 @@
|
||||
|
||||
package org.springframework.boot.configurationsample.endpoint;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.boot.configurationsample.Access;
|
||||
import org.springframework.boot.configurationsample.OptionalParameter;
|
||||
import org.springframework.boot.configurationsample.ReadOperation;
|
||||
import org.springframework.boot.configurationsample.WebEndpoint;
|
||||
|
||||
@@ -31,7 +32,7 @@ import org.springframework.boot.configurationsample.WebEndpoint;
|
||||
public class SpecificEndpoint {
|
||||
|
||||
@ReadOperation
|
||||
String invoke(@OptionalParameter String param) {
|
||||
String invoke(@Nullable String param) {
|
||||
return "test";
|
||||
}
|
||||
|
||||
|
||||
+3
-2
@@ -16,8 +16,9 @@
|
||||
|
||||
package org.springframework.boot.configurationsample.endpoint.incremental;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.boot.configurationsample.Endpoint;
|
||||
import org.springframework.boot.configurationsample.OptionalParameter;
|
||||
import org.springframework.boot.configurationsample.ReadOperation;
|
||||
|
||||
/**
|
||||
@@ -29,7 +30,7 @@ import org.springframework.boot.configurationsample.ReadOperation;
|
||||
public class IncrementalEndpoint {
|
||||
|
||||
@ReadOperation
|
||||
public String invoke(@OptionalParameter String param) {
|
||||
public String invoke(@Nullable String param) {
|
||||
return "test";
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -412,7 +412,7 @@ Operations on an endpoint receive input through their parameters.
|
||||
When exposed over the web, the values for these parameters are taken from the URL's query parameters and from the JSON request body.
|
||||
When exposed over JMX, the parameters are mapped to the parameters of the MBean's operations.
|
||||
Parameters are required by default.
|
||||
They can be made optional by annotating them with either javadoc:org.springframework.boot.actuate.endpoint.annotation.OptionalParameter[format=annotation] or JSpecify's javadoc:org.jspecify.annotations.Nullable[format=annotation].
|
||||
They can be made optional by annotating them with JSpecify's javadoc:org.jspecify.annotations.Nullable[format=annotation].
|
||||
Kotlin null safety is also supported.
|
||||
|
||||
You can map each root property in the JSON request body to a parameter of the endpoint.
|
||||
@@ -544,7 +544,7 @@ When using Spring MVC or Spring Web Flux, operations that return a javadoc:org.s
|
||||
==== Web Endpoint Security
|
||||
|
||||
An operation on a web endpoint or a web-specific endpoint extension can receive the current javadoc:java.security.Principal[] or javadoc:org.springframework.boot.actuate.endpoint.SecurityContext[] as a method parameter.
|
||||
The former is typically used in conjunction with either javadoc:org.springframework.boot.actuate.endpoint.annotation.OptionalParameter[format=annotation] or javadoc:org.jspecify.annotations.Nullable[format=annotation] to provide different behavior for authenticated and unauthenticated users.
|
||||
The former is typically used in conjunction with javadoc:org.jspecify.annotations.Nullable[format=annotation] to provide different behavior for authenticated and unauthenticated users.
|
||||
The latter is typically used to perform authorization checks by using its `isUserInRole(String)` method.
|
||||
|
||||
|
||||
|
||||
+4
-4
@@ -27,6 +27,7 @@ import java.util.function.BiConsumer;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
@@ -34,7 +35,6 @@ import reactor.core.publisher.Mono;
|
||||
import org.springframework.boot.actuate.endpoint.SecurityContext;
|
||||
import org.springframework.boot.actuate.endpoint.annotation.DeleteOperation;
|
||||
import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
|
||||
import org.springframework.boot.actuate.endpoint.annotation.OptionalParameter;
|
||||
import org.springframework.boot.actuate.endpoint.annotation.ReadOperation;
|
||||
import org.springframework.boot.actuate.endpoint.annotation.Selector;
|
||||
import org.springframework.boot.actuate.endpoint.annotation.Selector.Match;
|
||||
@@ -982,7 +982,7 @@ public abstract class AbstractWebEndpointIntegrationTests<T extends Configurable
|
||||
}
|
||||
|
||||
@WriteOperation
|
||||
void write(@OptionalParameter String foo, @OptionalParameter String bar) {
|
||||
void write(@Nullable String foo, @Nullable String bar) {
|
||||
this.endpointDelegate.write(foo, bar);
|
||||
}
|
||||
|
||||
@@ -1167,7 +1167,7 @@ public abstract class AbstractWebEndpointIntegrationTests<T extends Configurable
|
||||
static class RequiredParametersEndpoint {
|
||||
|
||||
@ReadOperation
|
||||
String read(String foo, @OptionalParameter String bar) {
|
||||
String read(String foo, @Nullable String bar) {
|
||||
return foo;
|
||||
}
|
||||
|
||||
@@ -1177,7 +1177,7 @@ public abstract class AbstractWebEndpointIntegrationTests<T extends Configurable
|
||||
static class PrincipalEndpoint {
|
||||
|
||||
@ReadOperation
|
||||
String read(@OptionalParameter Principal principal) {
|
||||
String read(@Nullable Principal principal) {
|
||||
return (principal != null) ? principal.getName() : "None";
|
||||
}
|
||||
|
||||
|
||||
+2
-3
@@ -24,7 +24,6 @@ import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.boot.actuate.endpoint.OperationResponseBody;
|
||||
import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
|
||||
import org.springframework.boot.actuate.endpoint.annotation.OptionalParameter;
|
||||
import org.springframework.boot.actuate.endpoint.annotation.ReadOperation;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
@@ -45,8 +44,8 @@ public class AuditEventsEndpoint {
|
||||
}
|
||||
|
||||
@ReadOperation
|
||||
public AuditEventsDescriptor events(@OptionalParameter @Nullable String principal,
|
||||
@OptionalParameter @Nullable OffsetDateTime after, @OptionalParameter @Nullable String type) {
|
||||
public AuditEventsDescriptor events(@Nullable String principal, @Nullable OffsetDateTime after,
|
||||
@Nullable String type) {
|
||||
List<AuditEvent> events = this.auditEventRepository.find(principal, getInstant(after), type);
|
||||
return new AuditEventsDescriptor(events);
|
||||
}
|
||||
|
||||
+1
-7
@@ -17,7 +17,6 @@
|
||||
package org.springframework.boot.actuate.endpoint.annotation;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Parameter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
@@ -27,7 +26,6 @@ import org.springframework.boot.actuate.endpoint.OperationType;
|
||||
import org.springframework.boot.actuate.endpoint.Producible;
|
||||
import org.springframework.boot.actuate.endpoint.invoke.reflect.OperationMethod;
|
||||
import org.springframework.core.annotation.AnnotationAttributes;
|
||||
import org.springframework.core.annotation.MergedAnnotations;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
@@ -42,7 +40,7 @@ public class DiscoveredOperationMethod extends OperationMethod {
|
||||
|
||||
public DiscoveredOperationMethod(Method method, OperationType operationType,
|
||||
AnnotationAttributes annotationAttributes) {
|
||||
super(method, operationType, DiscoveredOperationMethod::isOptionalParameter);
|
||||
super(method, operationType);
|
||||
Assert.notNull(annotationAttributes, "'annotationAttributes' must not be null");
|
||||
List<String> producesMediaTypes = new ArrayList<>();
|
||||
producesMediaTypes.addAll(Arrays.asList(annotationAttributes.getStringArray("produces")));
|
||||
@@ -50,10 +48,6 @@ public class DiscoveredOperationMethod extends OperationMethod {
|
||||
this.producesMediaTypes = Collections.unmodifiableList(producesMediaTypes);
|
||||
}
|
||||
|
||||
private static boolean isOptionalParameter(Parameter parameter) {
|
||||
return MergedAnnotations.from(parameter).isPresent(OptionalParameter.class);
|
||||
}
|
||||
|
||||
private <E extends Enum<E> & Producible<E>> List<String> getProducesFromProducible(
|
||||
AnnotationAttributes annotationAttributes) {
|
||||
Class<?> type = getProducesFrom(annotationAttributes);
|
||||
|
||||
-36
@@ -1,36 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-present the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.actuate.endpoint.annotation;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Annotation that indicates that an operation parameter is optional.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
* @since 4.0.0
|
||||
*/
|
||||
@Target({ ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
public @interface OptionalParameter {
|
||||
|
||||
}
|
||||
+1
-18
@@ -17,9 +17,7 @@
|
||||
package org.springframework.boot.actuate.endpoint.invoke.reflect;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Parameter;
|
||||
import java.util.Locale;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import org.springframework.boot.actuate.endpoint.OperationType;
|
||||
import org.springframework.boot.actuate.endpoint.invoke.OperationParameters;
|
||||
@@ -48,28 +46,13 @@ public class OperationMethod {
|
||||
* Create a new {@link OperationMethod} instance.
|
||||
* @param method the source method
|
||||
* @param operationType the operation type
|
||||
* @deprecated since 4.0.0 for removal in 4.2.0 in favor of
|
||||
* {@link #OperationMethod(Method, OperationType, Predicate)}
|
||||
*/
|
||||
@Deprecated(since = "4.0.0", forRemoval = true)
|
||||
public OperationMethod(Method method, OperationType operationType) {
|
||||
this(method, operationType, (parameter) -> false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new {@link OperationMethod} instance.
|
||||
* @param method the source method
|
||||
* @param operationType the operation type
|
||||
* @param optionalParameters predicate to test if a parameter is optional
|
||||
* @since 4.0.0
|
||||
*/
|
||||
public OperationMethod(Method method, OperationType operationType, Predicate<Parameter> optionalParameters) {
|
||||
Assert.notNull(method, "'method' must not be null");
|
||||
Assert.notNull(operationType, "'operationType' must not be null");
|
||||
this.method = method;
|
||||
this.operationType = operationType;
|
||||
this.operationParameters = new OperationMethodParameters(method, DEFAULT_PARAMETER_NAME_DISCOVERER,
|
||||
optionalParameters);
|
||||
this.operationParameters = new OperationMethodParameters(method, DEFAULT_PARAMETER_NAME_DISCOVERER);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+2
-11
@@ -18,7 +18,6 @@ package org.springframework.boot.actuate.endpoint.invoke.reflect;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Parameter;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import org.springframework.boot.actuate.endpoint.invoke.OperationParameter;
|
||||
import org.springframework.core.Nullness;
|
||||
@@ -35,18 +34,14 @@ class OperationMethodParameter implements OperationParameter {
|
||||
|
||||
private final Parameter parameter;
|
||||
|
||||
private final Predicate<Parameter> optional;
|
||||
|
||||
/**
|
||||
* Create a new {@link OperationMethodParameter} instance.
|
||||
* @param name the parameter name
|
||||
* @param parameter the parameter
|
||||
* @param optionalParameters predicate to test if a parameter is optional
|
||||
*/
|
||||
OperationMethodParameter(String name, Parameter parameter, Predicate<Parameter> optionalParameters) {
|
||||
OperationMethodParameter(String name, Parameter parameter) {
|
||||
this.name = name;
|
||||
this.parameter = parameter;
|
||||
this.optional = optionalParameters;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -61,11 +56,7 @@ class OperationMethodParameter implements OperationParameter {
|
||||
|
||||
@Override
|
||||
public boolean isMandatory() {
|
||||
return !isOptional();
|
||||
}
|
||||
|
||||
private boolean isOptional() {
|
||||
return Nullness.NULLABLE == Nullness.forParameter(this.parameter) || this.optional.test(this.parameter);
|
||||
return Nullness.NULLABLE != Nullness.forParameter(this.parameter);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+4
-9
@@ -22,7 +22,6 @@ import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
@@ -45,26 +44,22 @@ class OperationMethodParameters implements OperationParameters {
|
||||
* Create a new {@link OperationMethodParameters} instance.
|
||||
* @param method the source method
|
||||
* @param parameterNameDiscoverer the parameter name discoverer
|
||||
* @param optionalParameters predicate to test if a parameter is optional
|
||||
*/
|
||||
OperationMethodParameters(Method method, ParameterNameDiscoverer parameterNameDiscoverer,
|
||||
Predicate<Parameter> optionalParameters) {
|
||||
OperationMethodParameters(Method method, ParameterNameDiscoverer parameterNameDiscoverer) {
|
||||
Assert.notNull(method, "'method' must not be null");
|
||||
Assert.notNull(parameterNameDiscoverer, "'parameterNameDiscoverer' must not be null");
|
||||
Assert.notNull(optionalParameters, "'optionalParameters' must not be null");
|
||||
@Nullable String[] parameterNames = parameterNameDiscoverer.getParameterNames(method);
|
||||
Parameter[] parameters = method.getParameters();
|
||||
Assert.state(parameterNames != null, () -> "Failed to extract parameter names for " + method);
|
||||
this.operationParameters = getOperationParameters(parameters, parameterNames, optionalParameters);
|
||||
this.operationParameters = getOperationParameters(parameters, parameterNames);
|
||||
}
|
||||
|
||||
private List<OperationParameter> getOperationParameters(Parameter[] parameters, @Nullable String[] names,
|
||||
Predicate<Parameter> optionalParameters) {
|
||||
private List<OperationParameter> getOperationParameters(Parameter[] parameters, @Nullable String[] names) {
|
||||
List<OperationParameter> operationParameters = new ArrayList<>(parameters.length);
|
||||
for (int i = 0; i < names.length; i++) {
|
||||
String name = names[i];
|
||||
Assert.state(name != null, "'name' must not be null");
|
||||
operationParameters.add(new OperationMethodParameter(name, parameters[i], optionalParameters));
|
||||
operationParameters.add(new OperationMethodParameter(name, parameters[i]));
|
||||
}
|
||||
return Collections.unmodifiableList(operationParameters);
|
||||
}
|
||||
|
||||
+1
-2
@@ -34,7 +34,6 @@ import org.springframework.boot.actuate.endpoint.Sanitizer;
|
||||
import org.springframework.boot.actuate.endpoint.SanitizingFunction;
|
||||
import org.springframework.boot.actuate.endpoint.Show;
|
||||
import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
|
||||
import org.springframework.boot.actuate.endpoint.annotation.OptionalParameter;
|
||||
import org.springframework.boot.actuate.endpoint.annotation.ReadOperation;
|
||||
import org.springframework.boot.actuate.endpoint.annotation.Selector;
|
||||
import org.springframework.boot.context.properties.bind.PlaceholdersResolver;
|
||||
@@ -81,7 +80,7 @@ public class EnvironmentEndpoint {
|
||||
}
|
||||
|
||||
@ReadOperation
|
||||
public EnvironmentDescriptor environment(@OptionalParameter @Nullable String pattern) {
|
||||
public EnvironmentDescriptor environment(@Nullable String pattern) {
|
||||
boolean showUnsanitized = this.showValues.isShown(true);
|
||||
return getEnvironmentDescriptor(pattern, showUnsanitized);
|
||||
}
|
||||
|
||||
+1
-3
@@ -22,7 +22,6 @@ import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.boot.actuate.endpoint.SecurityContext;
|
||||
import org.springframework.boot.actuate.endpoint.Show;
|
||||
import org.springframework.boot.actuate.endpoint.annotation.OptionalParameter;
|
||||
import org.springframework.boot.actuate.endpoint.annotation.ReadOperation;
|
||||
import org.springframework.boot.actuate.endpoint.annotation.Selector;
|
||||
import org.springframework.boot.actuate.endpoint.web.WebEndpointResponse;
|
||||
@@ -53,8 +52,7 @@ public class EnvironmentEndpointWebExtension {
|
||||
}
|
||||
|
||||
@ReadOperation
|
||||
public EnvironmentDescriptor environment(SecurityContext securityContext,
|
||||
@OptionalParameter @Nullable String pattern) {
|
||||
public EnvironmentDescriptor environment(SecurityContext securityContext, @Nullable String pattern) {
|
||||
boolean showUnsanitized = this.showValues.isShown(securityContext, this.roles);
|
||||
return this.delegate.getEnvironmentDescriptor(pattern, showUnsanitized);
|
||||
}
|
||||
|
||||
+1
-2
@@ -29,7 +29,6 @@ import org.jspecify.annotations.Nullable;
|
||||
import org.springframework.aot.hint.annotation.RegisterReflectionForBinding;
|
||||
import org.springframework.boot.actuate.endpoint.OperationResponseBody;
|
||||
import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
|
||||
import org.springframework.boot.actuate.endpoint.annotation.OptionalParameter;
|
||||
import org.springframework.boot.actuate.endpoint.annotation.ReadOperation;
|
||||
import org.springframework.boot.actuate.endpoint.annotation.Selector;
|
||||
import org.springframework.boot.actuate.endpoint.annotation.WriteOperation;
|
||||
@@ -100,7 +99,7 @@ public class LoggersEndpoint {
|
||||
}
|
||||
|
||||
@WriteOperation
|
||||
public void configureLogLevel(@Selector String name, @OptionalParameter @Nullable LogLevel configuredLevel) {
|
||||
public void configureLogLevel(@Selector String name, @Nullable LogLevel configuredLevel) {
|
||||
Assert.notNull(name, "'name' must not be empty");
|
||||
LoggerGroup group = this.loggerGroups.get(name);
|
||||
if (group != null && group.hasMembers()) {
|
||||
|
||||
+1
-2
@@ -40,7 +40,6 @@ import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.boot.actuate.endpoint.Access;
|
||||
import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
|
||||
import org.springframework.boot.actuate.endpoint.annotation.OptionalParameter;
|
||||
import org.springframework.boot.actuate.endpoint.annotation.ReadOperation;
|
||||
import org.springframework.boot.actuate.endpoint.web.WebEndpointResponse;
|
||||
import org.springframework.boot.actuate.endpoint.web.annotation.WebEndpoint;
|
||||
@@ -78,7 +77,7 @@ public class HeapDumpWebEndpoint {
|
||||
}
|
||||
|
||||
@ReadOperation
|
||||
public WebEndpointResponse<Resource> heapDump(@OptionalParameter @Nullable Boolean live) {
|
||||
public WebEndpointResponse<Resource> heapDump(@Nullable Boolean live) {
|
||||
try {
|
||||
if (this.lock.tryLock(this.timeout, TimeUnit.MILLISECONDS)) {
|
||||
try {
|
||||
|
||||
+1
-3
@@ -29,7 +29,6 @@ import io.prometheus.metrics.model.snapshots.MetricSnapshots;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
|
||||
import org.springframework.boot.actuate.endpoint.annotation.OptionalParameter;
|
||||
import org.springframework.boot.actuate.endpoint.annotation.ReadOperation;
|
||||
import org.springframework.boot.actuate.endpoint.web.WebEndpointResponse;
|
||||
import org.springframework.boot.actuate.endpoint.web.annotation.WebEndpoint;
|
||||
@@ -69,8 +68,7 @@ public class PrometheusScrapeEndpoint {
|
||||
}
|
||||
|
||||
@ReadOperation(producesFrom = PrometheusOutputFormat.class)
|
||||
public WebEndpointResponse<byte[]> scrape(PrometheusOutputFormat format,
|
||||
@OptionalParameter @Nullable Set<String> includedNames) {
|
||||
public WebEndpointResponse<byte[]> scrape(PrometheusOutputFormat format, @Nullable Set<String> includedNames) {
|
||||
try {
|
||||
ByteArrayOutputStream outputStream = new ByteArrayOutputStream(this.nextMetricsScrapeSize);
|
||||
MetricSnapshots metricSnapshots = (includedNames != null)
|
||||
|
||||
+11
-45
@@ -16,19 +16,12 @@
|
||||
|
||||
package org.springframework.boot.actuate.endpoint.invoke.reflect;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Parameter;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.boot.actuate.endpoint.annotation.Selector;
|
||||
import org.springframework.boot.actuate.endpoint.annotation.Selector.Match;
|
||||
import org.springframework.core.annotation.MergedAnnotations;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
@@ -43,87 +36,60 @@ class OperationMethodParameterTests {
|
||||
|
||||
private final Method example = ReflectionUtils.findMethod(getClass(), "example", String.class, String.class);
|
||||
|
||||
private final Method exampleJSpecifyNullable = ReflectionUtils.findMethod(getClass(), "exampleJSpecifyNullable",
|
||||
String.class, String.class);
|
||||
|
||||
private final Method exampleSpringNullable = ReflectionUtils.findMethod(getClass(), "exampleSpringNullable",
|
||||
String.class, String.class);
|
||||
|
||||
private Method exampleAnnotation = ReflectionUtils.findMethod(getClass(), "exampleAnnotation", String.class);
|
||||
private final Method exampleAnnotation = ReflectionUtils.findMethod(getClass(), "exampleAnnotation", String.class);
|
||||
|
||||
@Test
|
||||
void getNameShouldReturnName() {
|
||||
OperationMethodParameter parameter = new OperationMethodParameter("name", this.example.getParameters()[0],
|
||||
this::isOptionalParameter);
|
||||
OperationMethodParameter parameter = new OperationMethodParameter("name", this.example.getParameters()[0]);
|
||||
assertThat(parameter.getName()).isEqualTo("name");
|
||||
}
|
||||
|
||||
@Test
|
||||
void getTypeShouldReturnType() {
|
||||
OperationMethodParameter parameter = new OperationMethodParameter("name", this.example.getParameters()[0],
|
||||
this::isOptionalParameter);
|
||||
OperationMethodParameter parameter = new OperationMethodParameter("name", this.example.getParameters()[0]);
|
||||
assertThat(parameter.getType()).isEqualTo(String.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
void isMandatoryWhenNoAnnotationShouldReturnTrue() {
|
||||
OperationMethodParameter parameter = new OperationMethodParameter("name", this.example.getParameters()[0],
|
||||
this::isOptionalParameter);
|
||||
OperationMethodParameter parameter = new OperationMethodParameter("name", this.example.getParameters()[0]);
|
||||
assertThat(parameter.isMandatory()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
void isMandatoryWhenOptionalAnnotationShouldReturnFalse() {
|
||||
OperationMethodParameter parameter = new OperationMethodParameter("name", this.example.getParameters()[1],
|
||||
this::isOptionalParameter);
|
||||
assertThat(parameter.isMandatory()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
void isMandatoryWhenJSpecifyNullableAnnotationShouldReturnFalse() {
|
||||
OperationMethodParameter parameter = new OperationMethodParameter("name",
|
||||
this.exampleJSpecifyNullable.getParameters()[1], this::isOptionalParameter);
|
||||
void isMandatoryWhenNullableAnnotationShouldReturnFalse() {
|
||||
OperationMethodParameter parameter = new OperationMethodParameter("name", this.example.getParameters()[1]);
|
||||
assertThat(parameter.isMandatory()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
@Deprecated(since = "4.0.0")
|
||||
void isMandatoryWhenSpringNullableAnnotationShouldReturnFalse() {
|
||||
OperationMethodParameter parameter = new OperationMethodParameter("name",
|
||||
this.exampleSpringNullable.getParameters()[1], this::isOptionalParameter);
|
||||
this.exampleSpringNullable.getParameters()[1]);
|
||||
assertThat(parameter.isMandatory()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
void getAnnotationShouldReturnAnnotation() {
|
||||
OperationMethodParameter parameter = new OperationMethodParameter("name",
|
||||
this.exampleAnnotation.getParameters()[0], this::isOptionalParameter);
|
||||
this.exampleAnnotation.getParameters()[0]);
|
||||
Selector annotation = parameter.getAnnotation(Selector.class);
|
||||
assertThat(annotation).isNotNull();
|
||||
assertThat(annotation.match()).isEqualTo(Match.ALL_REMAINING);
|
||||
}
|
||||
|
||||
private boolean isOptionalParameter(Parameter parameter) {
|
||||
return MergedAnnotations.from(parameter).isPresent(TestOptional.class);
|
||||
void example(String one, @org.jspecify.annotations.Nullable String two) {
|
||||
}
|
||||
|
||||
void example(String one, @TestOptional String two) {
|
||||
}
|
||||
|
||||
void exampleJSpecifyNullable(String one, @org.jspecify.annotations.Nullable String two) {
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
@Deprecated(since = "4.0.0")
|
||||
void exampleSpringNullable(String one, @org.springframework.lang.Nullable String two) {
|
||||
}
|
||||
|
||||
void exampleAnnotation(@Selector(match = Match.ALL_REMAINING) String allRemaining) {
|
||||
}
|
||||
|
||||
@Target({ ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
public @interface TestOptional {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+8
-14
@@ -17,12 +17,10 @@
|
||||
package org.springframework.boot.actuate.endpoint.invoke.reflect;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Parameter;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Spliterator;
|
||||
import java.util.Spliterators;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.stream.Stream;
|
||||
import java.util.stream.StreamSupport;
|
||||
|
||||
@@ -45,8 +43,6 @@ import static org.mockito.Mockito.mock;
|
||||
*/
|
||||
class OperationMethodParametersTests {
|
||||
|
||||
private static final Predicate<Parameter> NON_OPTIONAL = (parameter) -> false;
|
||||
|
||||
private final Method exampleMethod = ReflectionUtils.findMethod(getClass(), "example", String.class);
|
||||
|
||||
private final Method exampleNoParamsMethod = ReflectionUtils.findMethod(getClass(), "exampleNoParams");
|
||||
@@ -54,50 +50,48 @@ class OperationMethodParametersTests {
|
||||
@Test
|
||||
void createWhenMethodIsNullShouldThrowException() {
|
||||
assertThatIllegalArgumentException()
|
||||
.isThrownBy(() -> new OperationMethodParameters(null, mock(ParameterNameDiscoverer.class), NON_OPTIONAL))
|
||||
.isThrownBy(() -> new OperationMethodParameters(null, mock(ParameterNameDiscoverer.class)))
|
||||
.withMessageContaining("'method' must not be null");
|
||||
}
|
||||
|
||||
@Test
|
||||
void createWhenParameterNameDiscovererIsNullShouldThrowException() {
|
||||
assertThatIllegalArgumentException()
|
||||
.isThrownBy(() -> new OperationMethodParameters(this.exampleMethod, null, NON_OPTIONAL))
|
||||
assertThatIllegalArgumentException().isThrownBy(() -> new OperationMethodParameters(this.exampleMethod, null))
|
||||
.withMessageContaining("'parameterNameDiscoverer' must not be null");
|
||||
}
|
||||
|
||||
@Test
|
||||
void createWhenParameterNameDiscovererReturnsNullShouldThrowException() {
|
||||
assertThatIllegalStateException()
|
||||
.isThrownBy(() -> new OperationMethodParameters(this.exampleMethod, mock(ParameterNameDiscoverer.class),
|
||||
NON_OPTIONAL))
|
||||
.isThrownBy(() -> new OperationMethodParameters(this.exampleMethod, mock(ParameterNameDiscoverer.class)))
|
||||
.withMessageContaining("Failed to extract parameter names");
|
||||
}
|
||||
|
||||
@Test
|
||||
void hasParametersWhenHasParametersShouldReturnTrue() {
|
||||
OperationMethodParameters parameters = new OperationMethodParameters(this.exampleMethod,
|
||||
new DefaultParameterNameDiscoverer(), NON_OPTIONAL);
|
||||
new DefaultParameterNameDiscoverer());
|
||||
assertThat(parameters.hasParameters()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
void hasParametersWhenHasNoParametersShouldReturnFalse() {
|
||||
OperationMethodParameters parameters = new OperationMethodParameters(this.exampleNoParamsMethod,
|
||||
new DefaultParameterNameDiscoverer(), NON_OPTIONAL);
|
||||
new DefaultParameterNameDiscoverer());
|
||||
assertThat(parameters.hasParameters()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
void getParameterCountShouldReturnParameterCount() {
|
||||
OperationMethodParameters parameters = new OperationMethodParameters(this.exampleMethod,
|
||||
new DefaultParameterNameDiscoverer(), NON_OPTIONAL);
|
||||
new DefaultParameterNameDiscoverer());
|
||||
assertThat(parameters.getParameterCount()).isOne();
|
||||
}
|
||||
|
||||
@Test
|
||||
void iteratorShouldIterateOperationParameters() {
|
||||
OperationMethodParameters parameters = new OperationMethodParameters(this.exampleMethod,
|
||||
new DefaultParameterNameDiscoverer(), NON_OPTIONAL);
|
||||
new DefaultParameterNameDiscoverer());
|
||||
Iterator<OperationParameter> iterator = parameters.iterator();
|
||||
assertParameters(
|
||||
StreamSupport.stream(Spliterators.spliteratorUnknownSize(iterator, Spliterator.ORDERED), false));
|
||||
@@ -106,7 +100,7 @@ class OperationMethodParametersTests {
|
||||
@Test
|
||||
void streamShouldStreamOperationParameters() {
|
||||
OperationMethodParameters parameters = new OperationMethodParameters(this.exampleMethod,
|
||||
new DefaultParameterNameDiscoverer(), NON_OPTIONAL);
|
||||
new DefaultParameterNameDiscoverer());
|
||||
assertParameters(parameters.stream());
|
||||
}
|
||||
|
||||
|
||||
+5
-11
@@ -17,8 +17,6 @@
|
||||
package org.springframework.boot.actuate.endpoint.invoke.reflect;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Parameter;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
@@ -36,39 +34,35 @@ import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException
|
||||
*/
|
||||
class OperationMethodTests {
|
||||
|
||||
private static final Predicate<Parameter> NON_OPTIONAL = (parameter) -> false;
|
||||
|
||||
private final Method exampleMethod = ReflectionUtils.findMethod(getClass(), "example", String.class);
|
||||
|
||||
@Test
|
||||
void createWhenMethodIsNullShouldThrowException() {
|
||||
assertThatIllegalArgumentException()
|
||||
.isThrownBy(() -> new OperationMethod(null, OperationType.READ, NON_OPTIONAL))
|
||||
assertThatIllegalArgumentException().isThrownBy(() -> new OperationMethod(null, OperationType.READ))
|
||||
.withMessageContaining("'method' must not be null");
|
||||
}
|
||||
|
||||
@Test
|
||||
void createWhenOperationTypeIsNullShouldThrowException() {
|
||||
assertThatIllegalArgumentException()
|
||||
.isThrownBy(() -> new OperationMethod(this.exampleMethod, null, NON_OPTIONAL))
|
||||
assertThatIllegalArgumentException().isThrownBy(() -> new OperationMethod(this.exampleMethod, null))
|
||||
.withMessageContaining("'operationType' must not be null");
|
||||
}
|
||||
|
||||
@Test
|
||||
void getMethodShouldReturnMethod() {
|
||||
OperationMethod operationMethod = new OperationMethod(this.exampleMethod, OperationType.READ, NON_OPTIONAL);
|
||||
OperationMethod operationMethod = new OperationMethod(this.exampleMethod, OperationType.READ);
|
||||
assertThat(operationMethod.getMethod()).isEqualTo(this.exampleMethod);
|
||||
}
|
||||
|
||||
@Test
|
||||
void getOperationTypeShouldReturnOperationType() {
|
||||
OperationMethod operationMethod = new OperationMethod(this.exampleMethod, OperationType.READ, NON_OPTIONAL);
|
||||
OperationMethod operationMethod = new OperationMethod(this.exampleMethod, OperationType.READ);
|
||||
assertThat(operationMethod.getOperationType()).isEqualTo(OperationType.READ);
|
||||
}
|
||||
|
||||
@Test
|
||||
void getParametersShouldReturnParameters() {
|
||||
OperationMethod operationMethod = new OperationMethod(this.exampleMethod, OperationType.READ, NON_OPTIONAL);
|
||||
OperationMethod operationMethod = new OperationMethod(this.exampleMethod, OperationType.READ);
|
||||
OperationParameters parameters = operationMethod.getParameters();
|
||||
assertThat(parameters.getParameterCount()).isOne();
|
||||
assertThat(parameters.iterator().next().getName()).isEqualTo("name");
|
||||
|
||||
+4
-22
@@ -16,14 +16,9 @@
|
||||
|
||||
package org.springframework.boot.actuate.endpoint.invoke.reflect;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
import java.lang.reflect.Parameter;
|
||||
import java.util.Collections;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
@@ -33,7 +28,6 @@ import org.springframework.boot.actuate.endpoint.OperationType;
|
||||
import org.springframework.boot.actuate.endpoint.SecurityContext;
|
||||
import org.springframework.boot.actuate.endpoint.invoke.MissingParametersException;
|
||||
import org.springframework.boot.actuate.endpoint.invoke.ParameterValueMapper;
|
||||
import org.springframework.core.annotation.MergedAnnotations;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
@@ -58,7 +52,7 @@ class ReflectiveOperationInvokerTests {
|
||||
void setup() {
|
||||
this.target = new Example();
|
||||
this.operationMethod = new OperationMethod(ReflectionUtils.findMethod(Example.class, "reverse",
|
||||
ApiVersion.class, SecurityContext.class, String.class), OperationType.READ, this::isOptional);
|
||||
ApiVersion.class, SecurityContext.class, String.class), OperationType.READ);
|
||||
this.parameterValueMapper = (parameter, value) -> (value != null) ? value.toString() : null;
|
||||
}
|
||||
|
||||
@@ -103,8 +97,7 @@ class ReflectiveOperationInvokerTests {
|
||||
@Test
|
||||
void invokeWhenMissingOptionalArgumentShouldInvoke() {
|
||||
OperationMethod operationMethod = new OperationMethod(ReflectionUtils.findMethod(Example.class,
|
||||
"reverseOptional", ApiVersion.class, SecurityContext.class, String.class), OperationType.READ,
|
||||
this::isOptional);
|
||||
"reverseOptional", ApiVersion.class, SecurityContext.class, String.class), OperationType.READ);
|
||||
ReflectiveOperationInvoker invoker = new ReflectiveOperationInvoker(this.target, operationMethod,
|
||||
this.parameterValueMapper);
|
||||
Object result = invoker
|
||||
@@ -121,10 +114,6 @@ class ReflectiveOperationInvokerTests {
|
||||
assertThat(result).isEqualTo("4321");
|
||||
}
|
||||
|
||||
private boolean isOptional(Parameter parameter) {
|
||||
return MergedAnnotations.from(parameter).isPresent(TestOptional.class);
|
||||
}
|
||||
|
||||
static class Example {
|
||||
|
||||
String reverse(ApiVersion apiVersion, SecurityContext securityContext, String name) {
|
||||
@@ -133,7 +122,7 @@ class ReflectiveOperationInvokerTests {
|
||||
return new StringBuilder(name).reverse().toString();
|
||||
}
|
||||
|
||||
String reverseOptional(ApiVersion apiVersion, SecurityContext securityContext, @TestOptional String name) {
|
||||
String reverseOptional(ApiVersion apiVersion, SecurityContext securityContext, @Nullable String name) {
|
||||
assertThat(apiVersion).isEqualTo(ApiVersion.LATEST);
|
||||
assertThat(securityContext).isNotNull();
|
||||
return new StringBuilder(String.valueOf(name)).reverse().toString();
|
||||
@@ -141,11 +130,4 @@ class ReflectiveOperationInvokerTests {
|
||||
|
||||
}
|
||||
|
||||
@Target({ ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
public @interface TestOptional {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+7
-21
@@ -16,14 +16,10 @@
|
||||
|
||||
package org.springframework.boot.actuate.endpoint.invoker.cache;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.function.Function;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
@@ -38,7 +34,6 @@ import org.springframework.boot.actuate.endpoint.invoke.OperationInvoker;
|
||||
import org.springframework.boot.actuate.endpoint.invoke.OperationParameters;
|
||||
import org.springframework.boot.actuate.endpoint.invoke.reflect.OperationMethod;
|
||||
import org.springframework.boot.actuate.endpoint.web.WebServerNamespace;
|
||||
import org.springframework.core.annotation.MergedAnnotations;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
@@ -163,34 +158,32 @@ class CachingOperationInvokerAdvisorTests {
|
||||
|
||||
private OperationMethod getOperationMethod(String methodName, Class<?>... parameterTypes) {
|
||||
Method method = ReflectionUtils.findMethod(TestOperations.class, methodName, parameterTypes);
|
||||
return new OperationMethod(method, OperationType.READ,
|
||||
(parameter) -> MergedAnnotations.from(parameter).isPresent(TestOptional.class));
|
||||
return new OperationMethod(method, OperationType.READ);
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
static class TestOperations {
|
||||
|
||||
String get() {
|
||||
return "";
|
||||
}
|
||||
|
||||
String getWithParameters(@TestOptional String foo, String bar) {
|
||||
String getWithParameters(@Nullable String foo, String bar) {
|
||||
return "";
|
||||
}
|
||||
|
||||
String getWithAllOptionalParameters(@TestOptional String foo, @TestOptional String bar) {
|
||||
String getWithAllOptionalParameters(@Nullable String foo, @Nullable String bar) {
|
||||
return "";
|
||||
}
|
||||
|
||||
String getWithSecurityContext(SecurityContext securityContext, @TestOptional String bar) {
|
||||
String getWithSecurityContext(SecurityContext securityContext, @Nullable String bar) {
|
||||
return "";
|
||||
}
|
||||
|
||||
String getWithApiVersion(ApiVersion apiVersion, @TestOptional String bar) {
|
||||
String getWithApiVersion(ApiVersion apiVersion, @Nullable String bar) {
|
||||
return "";
|
||||
}
|
||||
|
||||
String getWithServerNamespace(WebServerNamespace serverNamespace, @TestOptional String bar) {
|
||||
String getWithServerNamespace(WebServerNamespace serverNamespace, @Nullable String bar) {
|
||||
return "";
|
||||
}
|
||||
|
||||
@@ -200,11 +193,4 @@ class CachingOperationInvokerAdvisorTests {
|
||||
|
||||
}
|
||||
|
||||
@Target({ ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
public @interface TestOptional {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+2
-4
@@ -27,7 +27,6 @@ import org.jspecify.annotations.Nullable;
|
||||
import org.springframework.boot.actuate.endpoint.OperationResponseBody;
|
||||
import org.springframework.boot.actuate.endpoint.annotation.DeleteOperation;
|
||||
import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
|
||||
import org.springframework.boot.actuate.endpoint.annotation.OptionalParameter;
|
||||
import org.springframework.boot.actuate.endpoint.annotation.ReadOperation;
|
||||
import org.springframework.boot.actuate.endpoint.annotation.Selector;
|
||||
import org.springframework.cache.Cache;
|
||||
@@ -82,8 +81,7 @@ public class CachesEndpoint {
|
||||
* {@code cacheManager} was provided to identify a unique candidate
|
||||
*/
|
||||
@ReadOperation
|
||||
public @Nullable CacheEntryDescriptor cache(@Selector String cache,
|
||||
@OptionalParameter @Nullable String cacheManager) {
|
||||
public @Nullable CacheEntryDescriptor cache(@Selector String cache, @Nullable String cacheManager) {
|
||||
return extractUniqueCacheEntry(cache, getCacheEntries((name) -> name.equals(cache), isNameMatch(cacheManager)));
|
||||
}
|
||||
|
||||
@@ -105,7 +103,7 @@ public class CachesEndpoint {
|
||||
* {@code cacheManager} was provided to identify a unique candidate
|
||||
*/
|
||||
@DeleteOperation
|
||||
public boolean clearCache(@Selector String cache, @OptionalParameter @Nullable String cacheManager) {
|
||||
public boolean clearCache(@Selector String cache, @Nullable String cacheManager) {
|
||||
CacheEntryDescriptor entry = extractUniqueCacheEntry(cache,
|
||||
getCacheEntries((name) -> name.equals(cache), isNameMatch(cacheManager)));
|
||||
return (entry != null && clearCache(entry));
|
||||
|
||||
+2
-5
@@ -19,7 +19,6 @@ package org.springframework.boot.cache.actuate.endpoint;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.boot.actuate.endpoint.annotation.DeleteOperation;
|
||||
import org.springframework.boot.actuate.endpoint.annotation.OptionalParameter;
|
||||
import org.springframework.boot.actuate.endpoint.annotation.ReadOperation;
|
||||
import org.springframework.boot.actuate.endpoint.annotation.Selector;
|
||||
import org.springframework.boot.actuate.endpoint.web.WebEndpointResponse;
|
||||
@@ -42,8 +41,7 @@ public class CachesEndpointWebExtension {
|
||||
}
|
||||
|
||||
@ReadOperation
|
||||
public WebEndpointResponse<CacheEntryDescriptor> cache(@Selector String cache,
|
||||
@OptionalParameter @Nullable String cacheManager) {
|
||||
public WebEndpointResponse<CacheEntryDescriptor> cache(@Selector String cache, @Nullable String cacheManager) {
|
||||
try {
|
||||
CacheEntryDescriptor entry = this.delegate.cache(cache, cacheManager);
|
||||
int status = (entry != null) ? WebEndpointResponse.STATUS_OK : WebEndpointResponse.STATUS_NOT_FOUND;
|
||||
@@ -55,8 +53,7 @@ public class CachesEndpointWebExtension {
|
||||
}
|
||||
|
||||
@DeleteOperation
|
||||
public WebEndpointResponse<Void> clearCache(@Selector String cache,
|
||||
@OptionalParameter @Nullable String cacheManager) {
|
||||
public WebEndpointResponse<Void> clearCache(@Selector String cache, @Nullable String cacheManager) {
|
||||
try {
|
||||
boolean cleared = this.delegate.clearCache(cache, cacheManager);
|
||||
int status = (cleared ? WebEndpointResponse.STATUS_NO_CONTENT : WebEndpointResponse.STATUS_NOT_FOUND);
|
||||
|
||||
+1
-3
@@ -37,7 +37,6 @@ import org.jspecify.annotations.Nullable;
|
||||
import org.springframework.boot.actuate.endpoint.InvalidEndpointRequestException;
|
||||
import org.springframework.boot.actuate.endpoint.OperationResponseBody;
|
||||
import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
|
||||
import org.springframework.boot.actuate.endpoint.annotation.OptionalParameter;
|
||||
import org.springframework.boot.actuate.endpoint.annotation.ReadOperation;
|
||||
import org.springframework.boot.actuate.endpoint.annotation.Selector;
|
||||
|
||||
@@ -78,8 +77,7 @@ public class MetricsEndpoint {
|
||||
}
|
||||
|
||||
@ReadOperation
|
||||
public @Nullable MetricDescriptor metric(@Selector String requiredMetricName,
|
||||
@OptionalParameter @Nullable List<String> tag) {
|
||||
public @Nullable MetricDescriptor metric(@Selector String requiredMetricName, @Nullable List<String> tag) {
|
||||
List<Tag> tags = parseTags(tag);
|
||||
Collection<Meter> meters = findFirstMatchingMeters(this.registry, requiredMetricName, tags);
|
||||
if (meters.isEmpty()) {
|
||||
|
||||
Reference in New Issue
Block a user