Support Optional for ProjectPayload arguments

Closes gh-506
This commit is contained in:
rstoyanchev
2022-10-17 17:27:44 +01:00
parent 560c2b53f2
commit 13683eea17
2 changed files with 113 additions and 9 deletions

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2021 the original author or authors.
* Copyright 2002-2022 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,8 @@
package org.springframework.graphql.data.method.annotation.support;
import java.util.Optional;
import graphql.schema.DataFetchingEnvironment;
import org.springframework.context.ApplicationContext;
@@ -77,24 +79,33 @@ public class ProjectedPayloadMethodArgumentResolver implements HandlerMethodArgu
@Override
public boolean supportsParameter(MethodParameter parameter) {
Class<?> type = parameter.getParameterType();
if (!type.isInterface()) {
return false;
}
return AnnotatedElementUtils.findMergedAnnotation(type, ProjectedPayload.class) != null;
Class<?> type = parameter.nestedIfOptional().getNestedParameterType();
return (type.isInterface() &&
AnnotatedElementUtils.findMergedAnnotation(type, ProjectedPayload.class) != null);
}
@Override
public Object resolveArgument(MethodParameter parameter, DataFetchingEnvironment environment) throws Exception {
String name = (parameter.hasParameterAnnotation(Argument.class) ?
ArgumentMethodArgumentResolver.getArgumentName(parameter) : null);
Class<?> projectionType = parameter.getParameterType();
boolean isOptional = parameter.isOptional();
if (isOptional) {
projectionType = parameter.nestedIfOptional().getNestedParameterType();
}
Object projectionSource = (name != null ?
environment.getArgument(name) : environment.getArguments());
return project(parameter.getParameterType(), projectionSource);
Object value = null;
if (!isOptional || projectionSource != null) {
value = project(projectionType, projectionSource);
}
return (isOptional ? Optional.ofNullable(value) : value);
}
protected Object project(Class<?> projectionType, Object projectionSource){

View File

@@ -0,0 +1,93 @@
/*
* Copyright 2020-2022 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.graphql.data.method.annotation.support;
import java.util.List;
import java.util.Optional;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.context.support.StaticApplicationContext;
import org.springframework.core.MethodParameter;
import org.springframework.data.web.ProjectedPayload;
import org.springframework.graphql.Book;
import org.springframework.graphql.data.method.annotation.Argument;
import org.springframework.graphql.data.method.annotation.QueryMapping;
import org.springframework.stereotype.Controller;
import static org.assertj.core.api.Assertions.assertThat;
/**
*
*/
public class ProjectedPayloadMethodArgumentResolverTests extends ArgumentResolverTestSupport {
private ProjectedPayloadMethodArgumentResolver resolver;
@BeforeEach
void setUp() {
StaticApplicationContext context = new StaticApplicationContext();
this.resolver = new ProjectedPayloadMethodArgumentResolver(context);
}
@Test
void supports() {
MethodParameter param = methodParam(BookController.class, "optionalProjection", Optional.class);
assertThat(this.resolver.supportsParameter(param)).isTrue();
param = methodParam(BookController.class, "optionalString", Optional.class);
assertThat(this.resolver.supportsParameter(param)).isFalse();
}
@Test
void optionalWrapper() throws Exception {
Object result = this.resolver.resolveArgument(
methodParam(BookController.class, "optionalProjection", Optional.class),
environment("{}"));
assertThat(result).isNotNull().isInstanceOf(Optional.class);
assertThat((Optional<?>) result).isNotPresent();
}
@SuppressWarnings({"ConstantConditions", "unused"})
@Controller
static class BookController {
@QueryMapping
public List<Book> optionalProjection(@Argument(name = "where") Optional<BookProjection> projection) {
return null;
}
@QueryMapping
public void optionalString(@Argument Optional<String> projection) {
}
}
@ProjectedPayload
interface BookProjection {
String getAuthor();
}
}