See #5506 for background
@philwebb Would it make sense to auto-configure a RestTemplate... I was pondering on that actually recently, to have a auto-configured RestTemplate which also _optionally_ could configure a HttpClient when in need of basic and/or ssl needs or detect a registered ClientHttpRequestFactory.
Although auto-configuring a HttpClient might be a separate topic.
Spring Cloud got out of the business of auto-configuring RestTemplate due to the fact that there could be two (one @LoadBalanced, one not). We have a RestTemplateCustomizer that we apply to the @LoadBalanced RestTemplate.
The intention of this issue is to provide a bean that can be used to create a RestTemplate with pre-configured message converters, not to provide a RestTemplate bean. That could either be some sort of factory that returns a new RestTemplate or a customiser that can be applied to a user-created RestTemplate instance.
Another observation: SpringBootTestContextCustomizer registers a bean of type RestTemplate but only in tests. This can really screw you up (if you want to autowire a RestTemplate anywhere and happen to create your own, or use UserInfoTokenServices).
Also, in Spring Cloud we have adopted a qualifier approach that might make sense here as well. If the user wants a load-balanced RestTemplate he declares a @Bean and marks it @LoadBalanced, and the framework injects the load balancer bits. We could do the same with message converters: the user marks a bean as @MessageConverters (or something better) and then he controls the creation and primariness (if necessary), and we just modify the converters.
Also relevant: #5202
@wilkinsona @philwebb @dsyer I am trying a few things and I ended up with a configurer approach (so that you can pass whatever RestTemplate implementation you want. Configuring a rest template boils down to:
@Bean
public RestTemplate restTemplate(RestTemplateConfigurer configurer) {
RestTemplate restTemplate = new RestTemplate();
configurer.configure(restTemplate);
return restTemplate;
}
Is it what you had in mind?
It's quite tricky because it's not a Configurer in the same sense as every other one that we support. I.e. it's not applied to configure existing RestTemplate beans. Perhaps a factory or a builder might be better? I'd also really like it if we could find some natural way to add in MockRestServiceServer without all the usual ceremony (see RemoteVehicleDetailsServiceTest).
Looking at RemoteVehicleDetailsService perhaps:
public RemoteVehicleDetailsService(RemoteVehicleDetailsServiceProperties properties, RestTemplateBuilder restTemplateBuilder) {
this.restTempate = restTemplateBuilder.build();
}
I'm not sure exactly what methods we'd have on the builder. Something to set a specific RestTemplate instance perhaps? A way to add more HttpMessageConverters? Add a ResponseErrorHandler or set a UriTemplateHandler? We could also support a DefaultUriTemplateHandler so you can set the URL just once.
We could make the builder immutable and possibly also encourage the use of RestOperations so that the result is also treated as immutable?
Perhaps RestOperations might be a way to bypass a lot of confusion actually:
public RemoteVehicleDetailsService(RemoteVehicleDetailsServiceProperties properties, RestBuilder restOperationsBuilder) {
this.restOperations = restBuilder.build(properties.getVehicleServiceRootUrl());
}
Well, if that's not right, something else is wrong :) JMS and Rabbit have similar configurers (we ended up with that name after a brainstorming with @wilkinsona).
We already know that a RestTemplate can be extended (there is an oauth2 one) so hard-coding to a specific implementation is not reaching the goal IMO. That's exactly the same reason why we came up with that approach for JMS (if you want to use OracleJMS, you have to extend our DefaultJmsMlessageListenerContainer for some reason).
Back to that brainstorming, I said I'd like a simple method to build an instance (and have no choice but to get a RestTemplate implementation) as well as a way to configure an existing instance. The outcome is that it was hard to find a good name for a class having both so we ended up with only the configure method and the Configurer prefix.
Unfortunately, the JMS/Rabbit ones have been added to 1.3 so we can't change them now.
I think the requirements are a bit different this time. An API similar to the framework's Jackson ObjectMapper builder might be a good fit. It has both a build method to get a new instance and a configure method to configure an existing instance.
@philwebb I've created #6030 and I already have a prototype almost working. The only issue left is that we need to reset the expectations between each test. I can see that @rstoyanchev has introduced a RequestExpectationManager in Spring Framework 4.3. I don't think that code is new, probably a refactoring, but it expects each test to have its own instance. Is there a way to improve that with a public reset method on AbstractRequestExpectationManager?
@bclozel I think I've addressed your concern in https://github.com/snicoll/spring-boot/commit/46fe440212e16692b2af821fc9f62321d8ca81cc:
RestTemplate configuration is one aspect of WebClientAutoConfiguration so we can add more in the futureRestTemplateBuilder now checks the classpath for a suitable ClientHttpRequestFactory. For now it only looks for Apache HTTP components but we can add more in the order we want.Does that work for you?
Yes!
I'm curious to see how developers will react to that - asking for more auto-configuration in that space or preferring total control over it.
Most helpful comment
The intention of this issue is to provide a bean that can be used to create a
RestTemplatewith pre-configured message converters, not to provide aRestTemplatebean. That could either be some sort of factory that returns a newRestTemplateor a customiser that can be applied to a user-createdRestTemplateinstance.