-
-
Save ripla/6f1516e3d0c28f4d591303d4060342d4 to your computer and use it in GitHub Desktop.
import java.util.Arrays; | |
import org.springframework.boot.web.client.RestTemplateBuilder; | |
import org.springframework.cloud.client.loadbalancer.LoadBalanced; | |
import org.springframework.context.annotation.Bean; | |
import org.springframework.context.annotation.Configuration; | |
import org.springframework.hateoas.MediaTypes; | |
import org.springframework.hateoas.hal.Jackson2HalModule; | |
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; | |
import org.springframework.web.client.RestTemplate; | |
import com.fasterxml.jackson.databind.DeserializationFeature; | |
import com.fasterxml.jackson.databind.ObjectMapper; | |
@Configuration | |
public class RestConfiguration { | |
@Bean | |
@LoadBalanced | |
public RestTemplate restTemplate(RestTemplateBuilder builder) { | |
ObjectMapper mapper = new ObjectMapper(); | |
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, | |
false); | |
mapper.registerModule(new Jackson2HalModule()); | |
MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter(); | |
converter.setSupportedMediaTypes(Arrays.asList(MediaTypes.HAL_JSON)); | |
converter.setObjectMapper(mapper); | |
return builder.messageConverters(converter).build(); | |
} | |
} |
import org.springframework.hateoas.Resources; | |
public class StudentResources extends Resources<Student> { | |
} |
import java.util.HashMap; | |
import java.util.Map; | |
import java.util.stream.Stream; | |
import org.springframework.beans.factory.annotation.Autowired; | |
import org.springframework.core.ParameterizedTypeReference; | |
import org.springframework.hateoas.PagedResources; | |
import org.springframework.hateoas.Resource; | |
import org.springframework.hateoas.Resources; | |
import org.springframework.hateoas.mvc.TypeReferences; | |
import org.springframework.http.HttpMethod; | |
import org.springframework.http.ResponseEntity; | |
import org.springframework.stereotype.Component; | |
import org.springframework.web.client.RestTemplate; | |
@Component | |
public class StudentsClient { | |
private static final String URL = "http://students-service/students?page={page}&size={size}"; | |
@Autowired | |
RestTemplate template; | |
public Stream<Student> getStudents(int offset, int limit) { | |
Map<String, Integer> params = new HashMap<>(); | |
params.put("page", offset / limit); | |
params.put("size", limit); | |
// Using external class | |
final ResponseEntity<StudentResources> studentResponse = template | |
.getForEntity(URL, StudentResources.class, params); | |
// Using instantiated ParametrizedTypeReference Resources | |
final ResponseEntity<Resources<Student>> studentResponse = template | |
.exchange(URL, HttpMethod.GET, null, | |
new ParameterizedTypeReference<Resources<Student>>() { | |
}, params); | |
// Using instantiated ParametrizedTypeReference Resources | |
final ResponseEntity<PagedResources<Student>> studentResponse = template | |
.exchange(URL, HttpMethod.GET, null, | |
new ParameterizedTypeReference<PagedResources<Student>>() { | |
}, params); | |
// Does not work for some reason, ends up with empty Resources inside Resources | |
// final ResponseEntity<Resources<Resource<Student>>> studentResponse = template | |
// .exchange(URL, HttpMethod.GET, null, | |
// new TypeReferences.ResourcesType<Resource<Student>>() { | |
// }, params); | |
// Using provided PagedResources type class, note the required {} | |
// This is used for return | |
final ResponseEntity<PagedResources<Resource<Student>>> studentResponse = | |
template | |
.exchange(URL, HttpMethod.GET, null, | |
new TypeReferences.PagedResourcesType<Resource<Student>>(){}, | |
params); | |
return studentResponse.getBody().getContent().stream() | |
.map(Resource::getContent); | |
} | |
} |
Definitely, this is a clean, clear and simple example of what I was looking half day. Thank you for taking the time to document and share this.
The clearest straightforward solution i was looking for
i really spent 2 days searching to achieve this.
Big thanks.
WoW~~ Thank U for your sweet coding!! I found the solution of my terrible headache!!
Have a good year to you!
works! Thanks a lot...
I also found this information: https://spring.io/blog/2020/04/22/spring-hateoas-brings-you-new-ways-to-configure-clients
autowire the hypermedia rest template configurer
@Autowired HypermediaRestTemplateConfigurer configurer
configure your rest template
RestTemplate restTemplate = configurer.registerHypermediaTypes(new RestTemplate())
use rest template
def result = restTemplate.exchange("...", HttpMethod.GET, new HttpEntity<Object>(new AddressDTO(...)), new ParameterizedTypeReference<CollectionModel<Address>>() {}, new HashMap<String, String>())
verify the result
result.body[0].lastName == 'testLastName'
thank you so much! I was also searching for hours!
works! Thanks a lot...
I also found this information: https://spring.io/blog/2020/04/22/spring-hateoas-brings-you-new-ways-to-configure-clientsautowire the hypermedia rest template configurer
@Autowired HypermediaRestTemplateConfigurer configurer
configure your rest template
RestTemplate restTemplate = configurer.registerHypermediaTypes(new RestTemplate())
use rest template
def result = restTemplate.exchange("...", HttpMethod.GET, new HttpEntity<Object>(new AddressDTO(...)), new ParameterizedTypeReference<CollectionModel<Address>>() {}, new HashMap<String, String>())
verify the result
result.body[0].lastName == 'testLastName'
I'm struggling now with List of Objects (simple Objects work!) that's why I wanted to change my Code to use the suggestion in the blog. I get the error "Could not autowire. No beans of 'HypermediaRestTemplateConfigurer' type found.". If I write the following:
@Bean
RestTemplateCustomizer restTemplateCustomizer(@Autowired
HypermediaRestTemplateConfigurer configurer) {
return restTemplate -> {
configurer.registerHypermediaTypes(restTemplate);
};
}
the problem isn't solved. Do you have an idea what I'm doing wrong?
Big thanks for this! Your RestConfiguration made my code work. The _embedded field is gone and became content.