Merge branch '6.2.x'
This commit is contained in:
commit
4a95b804e9
|
@ -988,6 +988,27 @@ parameter annotation) is set to `false`, or the parameter is marked optional as
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
[[rest-http-interface.custom-resolver]]
|
||||||
|
=== Custom argument resolver
|
||||||
|
|
||||||
|
For more complex cases, HTTP interfaces do not support `RequestEntity` types as method parameters.
|
||||||
|
This would take over the entire HTTP request and not improve the semantics of the interface.
|
||||||
|
Instead of adding many method parameters, developers can combine them into a custom type
|
||||||
|
and configure a dedicated `HttpServiceArgumentResolver` implementation.
|
||||||
|
|
||||||
|
In the following HTTP interface, we are using a custom `Search` type as a parameter:
|
||||||
|
|
||||||
|
include-code::./CustomHttpServiceArgumentResolver[tag=httpinterface,indent=0]
|
||||||
|
|
||||||
|
We can implement our own `HttpServiceArgumentResolver` that supports our custom `Search` type
|
||||||
|
and writes its data in the outgoing HTTP request.
|
||||||
|
|
||||||
|
include-code::./CustomHttpServiceArgumentResolver[tag=argumentresolver,indent=0]
|
||||||
|
|
||||||
|
Finally, we can use this argument resolver during the setup and use our HTTP interface.
|
||||||
|
|
||||||
|
include-code::./CustomHttpServiceArgumentResolver[tag=usage,indent=0]
|
||||||
|
|
||||||
[[rest-http-interface-return-values]]
|
[[rest-http-interface-return-values]]
|
||||||
=== Return Values
|
=== Return Values
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,105 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2002-2025 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.docs.integration.resthttpinterface.customresolver;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.springframework.core.MethodParameter;
|
||||||
|
import org.springframework.web.client.RestClient;
|
||||||
|
import org.springframework.web.client.support.RestClientAdapter;
|
||||||
|
import org.springframework.web.service.annotation.GetExchange;
|
||||||
|
import org.springframework.web.service.invoker.HttpRequestValues;
|
||||||
|
import org.springframework.web.service.invoker.HttpServiceArgumentResolver;
|
||||||
|
import org.springframework.web.service.invoker.HttpServiceProxyFactory;
|
||||||
|
|
||||||
|
public class CustomHttpServiceArgumentResolver {
|
||||||
|
|
||||||
|
// tag::httpinterface[]
|
||||||
|
interface RepositoryService {
|
||||||
|
|
||||||
|
@GetExchange("/repos/search")
|
||||||
|
List<Repository> searchRepository(Search search);
|
||||||
|
|
||||||
|
}
|
||||||
|
// end::httpinterface[]
|
||||||
|
|
||||||
|
class Sample {
|
||||||
|
|
||||||
|
void sample() {
|
||||||
|
// tag::usage[]
|
||||||
|
RestClient restClient = RestClient.builder().baseUrl("https://api.github.com/").build();
|
||||||
|
RestClientAdapter adapter = RestClientAdapter.create(restClient);
|
||||||
|
HttpServiceProxyFactory factory = HttpServiceProxyFactory
|
||||||
|
.builderFor(adapter)
|
||||||
|
.customArgumentResolver(new SearchQueryArgumentResolver())
|
||||||
|
.build();
|
||||||
|
RepositoryService repositoryService = factory.createClient(RepositoryService.class);
|
||||||
|
|
||||||
|
Search search = Search.create()
|
||||||
|
.owner("spring-projects")
|
||||||
|
.language("java")
|
||||||
|
.query("rest")
|
||||||
|
.build();
|
||||||
|
List<Repository> repositories = repositoryService.searchRepository(search);
|
||||||
|
// end::usage[]
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// tag::argumentresolver[]
|
||||||
|
static class SearchQueryArgumentResolver implements HttpServiceArgumentResolver {
|
||||||
|
@Override
|
||||||
|
public boolean resolve(Object argument, MethodParameter parameter, HttpRequestValues.Builder requestValues) {
|
||||||
|
if (parameter.getParameterType().equals(Search.class)) {
|
||||||
|
Search search = (Search) argument;
|
||||||
|
requestValues.addRequestParameter("owner", search.owner());
|
||||||
|
requestValues.addRequestParameter("language", search.language());
|
||||||
|
requestValues.addRequestParameter("query", search.query());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// end::argumentresolver[]
|
||||||
|
|
||||||
|
|
||||||
|
record Search (String query, String owner, String language) {
|
||||||
|
|
||||||
|
static Builder create() {
|
||||||
|
return new Builder();
|
||||||
|
}
|
||||||
|
|
||||||
|
static class Builder {
|
||||||
|
|
||||||
|
Builder query(String query) { return this;}
|
||||||
|
|
||||||
|
Builder owner(String owner) { return this;}
|
||||||
|
|
||||||
|
Builder language(String language) { return this;}
|
||||||
|
|
||||||
|
Search build() {
|
||||||
|
return new Search(null, null, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
record Repository(String name) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,77 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2002-2025 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.docs.integration.resthttpinterface.customresolver
|
||||||
|
|
||||||
|
import org.springframework.core.MethodParameter
|
||||||
|
import org.springframework.web.client.RestClient
|
||||||
|
import org.springframework.web.client.support.RestClientAdapter
|
||||||
|
import org.springframework.web.service.annotation.GetExchange
|
||||||
|
import org.springframework.web.service.invoker.HttpRequestValues
|
||||||
|
import org.springframework.web.service.invoker.HttpServiceArgumentResolver
|
||||||
|
import org.springframework.web.service.invoker.HttpServiceProxyFactory
|
||||||
|
|
||||||
|
class CustomHttpServiceArgumentResolver {
|
||||||
|
|
||||||
|
// tag::httpinterface[]
|
||||||
|
interface RepositoryService {
|
||||||
|
|
||||||
|
@GetExchange("/repos/search")
|
||||||
|
fun searchRepository(search: Search): List<Repository>
|
||||||
|
|
||||||
|
}
|
||||||
|
// end::httpinterface[]
|
||||||
|
|
||||||
|
class Sample {
|
||||||
|
fun sample() {
|
||||||
|
// tag::usage[]
|
||||||
|
val restClient = RestClient.builder().baseUrl("https://api.github.com/").build()
|
||||||
|
val adapter = RestClientAdapter.create(restClient)
|
||||||
|
val factory = HttpServiceProxyFactory
|
||||||
|
.builderFor(adapter)
|
||||||
|
.customArgumentResolver(SearchQueryArgumentResolver())
|
||||||
|
.build()
|
||||||
|
val repositoryService = factory.createClient<RepositoryService?>(RepositoryService::class.java)
|
||||||
|
|
||||||
|
val search = Search(owner = "spring-projects", language = "java", query = "rest")
|
||||||
|
val repositories = repositoryService.searchRepository(search)
|
||||||
|
// end::usage[]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// tag::argumentresolver[]
|
||||||
|
class SearchQueryArgumentResolver : HttpServiceArgumentResolver {
|
||||||
|
override fun resolve(
|
||||||
|
argument: Any?,
|
||||||
|
parameter: MethodParameter,
|
||||||
|
requestValues: HttpRequestValues.Builder
|
||||||
|
): Boolean {
|
||||||
|
if (parameter.getParameterType() == Search::class.java) {
|
||||||
|
val search = argument as Search
|
||||||
|
requestValues.addRequestParameter("owner", search.owner)
|
||||||
|
.addRequestParameter("language", search.language)
|
||||||
|
.addRequestParameter("query", search.query)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// end::argumentresolver[]
|
||||||
|
|
||||||
|
data class Search(val query: String, val owner: String, val language: String)
|
||||||
|
|
||||||
|
data class Repository(val name: String)
|
||||||
|
}
|
Loading…
Reference in New Issue