Use OperationParameter consistently

Closes gh-31240
This commit is contained in:
Moritz Halbritter 2023-01-16 11:17:13 +01:00
parent a2f9e30e77
commit 96175a8e50
7 changed files with 77 additions and 29 deletions

View File

@ -1,5 +1,5 @@
/*
* Copyright 2012-2019 the original author or authors.
* Copyright 2012-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -16,6 +16,7 @@
package org.springframework.boot.actuate.autoconfigure.endpoint;
import java.lang.annotation.Annotation;
import java.util.Collections;
import java.util.Set;
@ -200,6 +201,11 @@ class EndpointAutoConfigurationTests {
return false;
}
@Override
public <T extends Annotation> T getAnnotation(Class<T> annotation) {
return null;
}
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2012-2019 the original author or authors.
* Copyright 2012-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -16,10 +16,13 @@
package org.springframework.boot.actuate.endpoint.invoke;
import java.lang.annotation.Annotation;
/**
* A single operation parameter.
*
* @author Phillip Webb
* @author Moritz Halbritter
* @since 2.0.0
*/
public interface OperationParameter {
@ -42,4 +45,13 @@ public interface OperationParameter {
*/
boolean isMandatory();
/**
* Returns this element's annotation for the specified type if such an annotation is
* present, else null.
* @param annotation class of the annotation
* @return annotation value
* @param <T> type of the annotation
*/
<T extends Annotation> T getAnnotation(Class<T> annotation);
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2012-2021 the original author or authors.
* Copyright 2012-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -16,6 +16,7 @@
package org.springframework.boot.actuate.endpoint.invoke.reflect;
import java.lang.annotation.Annotation;
import java.lang.reflect.Parameter;
import javax.annotation.Nonnull;
@ -32,6 +33,7 @@ import org.springframework.util.ObjectUtils;
* {@link OperationParameter} created from an {@link OperationMethod}.
*
* @author Phillip Webb
* @author Moritz Halbritter
*/
class OperationMethodParameter implements OperationParameter {
@ -69,6 +71,11 @@ class OperationMethodParameter implements OperationParameter {
return (jsr305Present) ? new Jsr305().isMandatory(this.parameter) : true;
}
@Override
public <T extends Annotation> T getAnnotation(Class<T> annotation) {
return this.parameter.getAnnotation(annotation);
}
@Override
public String toString() {
return this.name + " of type " + this.parameter.getType().getName();

View File

@ -1,5 +1,5 @@
/*
* Copyright 2012-2019 the original author or authors.
* Copyright 2012-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -16,10 +16,7 @@
package org.springframework.boot.actuate.endpoint.web.annotation;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.reactivestreams.Publisher;
@ -28,6 +25,8 @@ import org.springframework.boot.actuate.endpoint.annotation.AbstractDiscoveredOp
import org.springframework.boot.actuate.endpoint.annotation.DiscoveredOperationMethod;
import org.springframework.boot.actuate.endpoint.annotation.Selector;
import org.springframework.boot.actuate.endpoint.invoke.OperationInvoker;
import org.springframework.boot.actuate.endpoint.invoke.OperationParameter;
import org.springframework.boot.actuate.endpoint.invoke.reflect.OperationMethod;
import org.springframework.boot.actuate.endpoint.web.WebOperation;
import org.springframework.boot.actuate.endpoint.web.WebOperationRequestPredicate;
import org.springframework.core.style.ToStringCreator;
@ -39,6 +38,7 @@ import org.springframework.util.ClassUtils;
* @author Andy Wilkinson
* @author Stephane Nicoll
* @author Phillip Webb
* @author Moritz Halbritter
*/
class DiscoveredWebOperation extends AbstractDiscoveredOperation implements WebOperation {
@ -54,27 +54,26 @@ class DiscoveredWebOperation extends AbstractDiscoveredOperation implements WebO
DiscoveredWebOperation(EndpointId endpointId, DiscoveredOperationMethod operationMethod, OperationInvoker invoker,
WebOperationRequestPredicate requestPredicate) {
super(operationMethod, invoker);
Method method = operationMethod.getMethod();
this.id = getId(endpointId, method);
this.blocking = getBlocking(method);
this.id = getId(endpointId, operationMethod);
this.blocking = getBlocking(operationMethod);
this.requestPredicate = requestPredicate;
}
private String getId(EndpointId endpointId, Method method) {
return endpointId + Stream.of(method.getParameters()).filter(this::hasSelector).map(this::dashName)
private String getId(EndpointId endpointId, OperationMethod method) {
return endpointId + method.getParameters().stream().filter(this::hasSelector).map(this::dashName)
.collect(Collectors.joining());
}
private boolean hasSelector(Parameter parameter) {
private boolean hasSelector(OperationParameter parameter) {
return parameter.getAnnotation(Selector.class) != null;
}
private String dashName(Parameter parameter) {
private String dashName(OperationParameter parameter) {
return "-" + parameter.getName();
}
private boolean getBlocking(Method method) {
return !REACTIVE_STREAMS_PRESENT || !Publisher.class.isAssignableFrom(method.getReturnType());
private boolean getBlocking(OperationMethod method) {
return !REACTIVE_STREAMS_PRESENT || !Publisher.class.isAssignableFrom(method.getMethod().getReturnType());
}
@Override

View File

@ -1,5 +1,5 @@
/*
* Copyright 2012-2019 the original author or authors.
* Copyright 2012-2023 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.
@ -17,8 +17,6 @@
package org.springframework.boot.actuate.endpoint.web.annotation;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.stream.Stream;
@ -27,6 +25,7 @@ import org.springframework.boot.actuate.endpoint.OperationType;
import org.springframework.boot.actuate.endpoint.annotation.DiscoveredOperationMethod;
import org.springframework.boot.actuate.endpoint.annotation.Selector;
import org.springframework.boot.actuate.endpoint.annotation.Selector.Match;
import org.springframework.boot.actuate.endpoint.invoke.OperationParameter;
import org.springframework.boot.actuate.endpoint.web.EndpointMediaTypes;
import org.springframework.boot.actuate.endpoint.web.WebEndpointHttpMethod;
import org.springframework.boot.actuate.endpoint.web.WebEndpointResponse;
@ -41,6 +40,7 @@ import org.springframework.util.Assert;
* @author Andy Wilkinson
* @author Stephane Nicoll
* @author Phillip Webb
* @author Moritz Halbritter
*/
class RequestPredicateFactory {
@ -53,9 +53,9 @@ class RequestPredicateFactory {
WebOperationRequestPredicate getRequestPredicate(String rootPath, DiscoveredOperationMethod operationMethod) {
Method method = operationMethod.getMethod();
Parameter[] selectorParameters = Arrays.stream(method.getParameters()).filter(this::hasSelector)
.toArray(Parameter[]::new);
Parameter allRemainingPathSegmentsParameter = getAllRemainingPathSegmentsParameter(selectorParameters);
OperationParameter[] selectorParameters = operationMethod.getParameters().stream().filter(this::hasSelector)
.toArray(OperationParameter[]::new);
OperationParameter allRemainingPathSegmentsParameter = getAllRemainingPathSegmentsParameter(selectorParameters);
String path = getPath(rootPath, selectorParameters, allRemainingPathSegmentsParameter != null);
WebEndpointHttpMethod httpMethod = determineHttpMethod(operationMethod.getOperationType());
Collection<String> consumes = getConsumes(httpMethod, method);
@ -63,9 +63,9 @@ class RequestPredicateFactory {
return new WebOperationRequestPredicate(path, httpMethod, consumes, produces);
}
private Parameter getAllRemainingPathSegmentsParameter(Parameter[] selectorParameters) {
Parameter trailingPathsParameter = null;
for (Parameter selectorParameter : selectorParameters) {
private OperationParameter getAllRemainingPathSegmentsParameter(OperationParameter[] selectorParameters) {
OperationParameter trailingPathsParameter = null;
for (OperationParameter selectorParameter : selectorParameters) {
Selector selector = selectorParameter.getAnnotation(Selector.class);
if (selector.match() == Match.ALL_REMAINING) {
Assert.state(trailingPathsParameter == null,
@ -80,7 +80,8 @@ class RequestPredicateFactory {
return trailingPathsParameter;
}
private String getPath(String rootPath, Parameter[] selectorParameters, boolean matchRemainingPathSegments) {
private String getPath(String rootPath, OperationParameter[] selectorParameters,
boolean matchRemainingPathSegments) {
StringBuilder path = new StringBuilder(rootPath);
for (int i = 0; i < selectorParameters.length; i++) {
path.append("/{");
@ -93,7 +94,7 @@ class RequestPredicateFactory {
return path.toString();
}
private boolean hasSelector(Parameter parameter) {
private boolean hasSelector(OperationParameter parameter) {
return parameter.getAnnotation(Selector.class) != null;
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2012-2022 the original author or authors.
* Copyright 2012-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -16,6 +16,7 @@
package org.springframework.boot.actuate.endpoint.invoke.convert;
import java.lang.annotation.Annotation;
import java.time.OffsetDateTime;
import org.junit.jupiter.api.Test;
@ -104,6 +105,11 @@ class ConversionServiceParameterValueMapperTests {
return false;
}
@Override
public <T extends Annotation> T getAnnotation(Class<T> annotation) {
return null;
}
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2012-2021 the original author or authors.
* Copyright 2012-2023 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.
@ -26,6 +26,8 @@ import javax.annotation.meta.When;
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.lang.Nullable;
import org.springframework.util.ReflectionUtils;
@ -35,6 +37,7 @@ import static org.assertj.core.api.Assertions.assertThat;
* Tests for {@link OperationMethodParameter}.
*
* @author Phillip Webb
* @author Moritz Halbritter
*/
class OperationMethodParameterTests {
@ -48,6 +51,8 @@ class OperationMethodParameterTests {
private Method exampleJsr305NonNull = ReflectionUtils.findMethod(getClass(), "exampleJsr305NonNull", String.class,
String.class);
private Method exampleAnnotation = ReflectionUtils.findMethod(getClass(), "exampleAnnotation", String.class);
@Test
void getNameShouldReturnName() {
OperationMethodParameter parameter = new OperationMethodParameter("name", this.example.getParameters()[0]);
@ -93,6 +98,15 @@ class OperationMethodParameterTests {
assertThat(parameter.isMandatory()).isTrue();
}
@Test
void getAnnotationShouldReturnAnnotation() {
OperationMethodParameter parameter = new OperationMethodParameter("name",
this.exampleAnnotation.getParameters()[0]);
Selector annotation = parameter.getAnnotation(Selector.class);
assertThat(annotation).isNotNull();
assertThat(annotation.match()).isEqualTo(Match.ALL_REMAINING);
}
void example(String one, @Nullable String two) {
}
@ -105,6 +119,9 @@ class OperationMethodParameterTests {
void exampleJsr305NonNull(String one, @javax.annotation.Nonnull String two) {
}
void exampleAnnotation(@Selector(match = Match.ALL_REMAINING) String allRemaining) {
}
@TypeQualifier
@Retention(RetentionPolicy.RUNTIME)
@Nonnull(when = When.MAYBE)