Spring boot equivalent of DropwizardAppExtension? - java

I'm currently porting my app from Drop Wizard to Spring Boot. But, I cant find a equivalent for DropwizardAppExtension.
For example:
private static final ResourceExtension resource = ResourceExtension.builder()
.addResource(new Controller(NEO4J_CLIENT))
.build();
#Test
public void myTest() {
final Invocation.Builder request = resource.target("/documents")
.queryParam("ids", "111")
.request();
Map<String, Object> response = request.get(TYPED_MAP);
assertEquals(expectedResponse, response);
}
Does anyone know if there is a Spring boot equivalent for DropwizardAppExtension? How would I create simular tests using spring-boot-starter-test?

Related

How to mock an dependency when passed as an argument?

We created a common class where a RestTemplate is passed as a parameter. This rest template is used to facilitate:
postForEntity
exchange
However, since it is not Autowired in the common class, I am not able to create unit tests that mocks the RestTemplate. Is there a work around for this?
Setup:
Spring boot Project A - initiates a rest integration and utilises the common class. This Project A instantiates the #Autowired RestTemplate rest template and pass it as a parameter to the common class method.
Spring boot Common Class - conducts the rest integration but uses the rest template passed by Project A. This common class I am unable to conduct the unit test since I cannot mock the Rest Template.
This is a java spring boot project.
Addendum:
**COMMON CLASS
public class RestService {
public static void invoke(RestTemplate restTemplate, RequestDetails requestDetails) {
switch (requestDetails.getHttpMethod()) {
case POST:
HttpEntity<?> postEntity = new HttpEntity<>(request, httpHeaders);
restResponse = restTemplate.postForEntity(requestDetails.getUrl(), postEntity, String.class);
break;
case GET:
HttpEntity<?> getEntity = new HttpEntity<>(httpHeaders);
restResponse = restTemplate.exchange(requestDetails.getUrl(),
HttpMethod.GET, getEntity, String.class);
break;
default:
break;
}
}
}
** INVOKING CLASS
public class InvokingClass {
#Autowired
private RestTemplate restTemplate;
public void invoke() {
//RequestDetails construct here ...
RestService.invoke(restTemplate,requestDetails)
}
}
I'm not sure what you are trying to achieve. If you want to test your RestService you should be able to do something like this:
#Test
void test() {
RestTemplate templateMock = mock(RestTemplate.class);
RestService.invoke(templateMock, new RequestDetails());
verify(templateMock).postForEntity(any(URI.class), any(Object.class), any(Class.class));
}
If this is not what you're looking for please provide more details on what you're trying to test. Thanks.

Can we use #RestClientTest when the rest template has interceptors using Spring boot 1.5.x?

I am using Spring Boot 1.5.x (Spring 4.2.x), and I created a RestClientSdk spring component class as shown here:
#Component
public class RestClientSdkImpl implements RestClientSdk {
private RestTemplate restTemplate;
#Autowired
public RestClientSdkImpl(RestTemplateBuilder restTemplateBuilder) {
this.restTemplate = restTemplateBuilder.build();
}
...
//other methods kept out for brevity
}
I have also defined a DefaultRestTemplateCustomizer spring component as shown here:
#Component
public class DefaultRestTemplateCustomizer implements RestTemplateCustomizer {
private LogClientHttpRequestInterceptor logClientHttpRequestInterceptor;
#Autowired
public DefaultRestTemplateCustomizer(LogClientHttpRequestInterceptor logClientHttpRequestInterceptor) {
this.logClientHttpRequestInterceptor = logClientHttpRequestInterceptor;
}
#Override
public void customize(RestTemplate restTemplate) {
restTemplate.getInterceptors().add(logClientHttpRequestInterceptor);
restTemplate.setRequestFactory(new BufferingClientHttpRequestFactory(new SimpleClientHttpRequestFactory()));
}
}
With that, I've defined a test class as shown below that uses the #RestClientTest annotation as shown below.
#RunWith(SpringRunner.class)
#RestClientTest(RestClientSdk.class)
#ActiveProfiles("test")
/*
* The RestClientTest only includes the most minimal configuration to include a rest template builder,
* so we include the rest sdk auto config within the scope of the test
*/
#ImportAutoConfiguration(RestSdkAutoConfiguration.class)
public class RestClientApplicationBehaviourTest{
#Autowired
private RestClientSdk restClientSdk;
#Autowired
private MockRestServiceServer mockRestServiceServer;
/**
* A simple Http Get that retrieves a JSON document from a rest server and
* produces a plain old java object as a response.
*/
#Test
public void testPlainHttpGet() throws IOException{
//ARRANGE
RestClientDto<?> simpleGetRequest = simpleHttpGet();
mockRestServiceServer.expect(once(), requestTo("http://localhost:8080/account/1234567890"))
.andRespond(withSuccess(IOUtils.getInputAsString("/stubs/account.json"),MediaType.APPLICATION_JSON));
//ACT
Account account = restClientSdk.send(simpleGetRequest, Account.class);
//ASSERT
mockRestServiceServer.verify();
Assert.assertNotNull(account);
Assert.assertNotNull(account.getAccountId());
Assert.assertNotNull(account.getFirstName());
Assert.assertNotNull(account.getLastName());
}
...
//not including other methods for brevity
}
PROBLEM
Because the MockRestServiceServer builder overrides the BufferingClientHttpRequestFactory in my rest template with a MockClientHttpRequestFactory, I am getting a null response from my body. This is because the logging interceptor is reading the input stream coming from the response and as such the stream no longer has content to read. The BufferingClientHttpRequestFactory would prevent that from happening. Now, I know that as of Spring 5.0.5, there is an extra option in the MockRestServiceServer builder called bufferContent, but I don't have the option of moving to Spring 5.x (Spring Boot 2.x), so I was wondering if there is a way to get this configured using Spring Boot 1.5.x / Spring 4.2.x.
I thank you in advance!
Juan
In order to workaround the issue, I needed to define a test configuration, that would allow me to override the client request factory. Please see the code below. It is a bit hacky, but I suppose the real solution here would be to upgrade to Spring 5.x / Spring Boot 2.x.
#Configuration
#Profile("test")
public class MockRestServiceServerConfiguration {
/**
* Wrap the Mock Rest client factory in the buffered one.
* #param restClientSdk The rest client SDK containing the rest template to use.
* #return The mock rest service server to use.
*/
#Bean
public MockRestServiceServer mockRestServiceServer(RestClientSdkImpl restClientSdkImpl) {
RestTemplate restTemplate = restClientSdkImpl.getRestTemplate();
MockRestServiceServer server = MockRestServiceServer.createServer(restTemplate);
//need to do this because getRequestFactory returns InterceptingHttpRequestFactory wraping the mock rest service server request factory
List<ClientHttpRequestInterceptor> templateInterceptors = restTemplate.getInterceptors();
restTemplate.setInterceptors(null);
//now we wrap the delegate, which should be the mock rest service server request factory
BufferingClientHttpRequestFactory bufferingFact = new BufferingClientHttpRequestFactory(restTemplate.getRequestFactory());
restTemplate.setRequestFactory(bufferingFact);
restTemplate.setInterceptors(templateInterceptors);
return server;
}
}

Spring Cloud microservice, consume password protected micro service with other micro service

currently I'm following some tutorials to create micro services in java with spring and the neflix stack.
One problem I have is that every service I start seems to be protected by a generated password. So it is not possible for another microservice to use another one because of this.
So what is the best and common way for one micro service to consume another via a rest call? Do I have to ajust the application.yml further and how?
Here is an example (very rough and basic). I have a micro service that calls another one with the following function:
#RestController
#SpringBootApplication
public class BookstoreApplication {
#RequestMapping(value = "/recommended")
public String readingList(){
return "Spring in Action (Manning), Cloud Native Java (O'Reilly), Learning Spring Boot (Packt)";
}
public static void main(String[] args) {
System.setProperty("spring.config.name", "springTut2CircuitBreakers/circuitApplication");
SpringApplication.run(BookstoreApplication.class, args);
}
}
The other micro service is listening to that call with following code:
#RestController
#SpringBootApplication
public class ReadingApplication {
#RequestMapping("/to-read")
public String readingList() {
RestTemplate restTemplate = new RestTemplate();
URI uri = URI.create("http://localhost:8090/recommended");
return restTemplate.getForObject(uri, String.class);
}
public static void main(String[] args) {
System.setProperty("spring.config.name", "springTut2CircuitBreakers/readingApplication");
SpringApplication.run(ReadingApplication.class, args);
}
}
When I try to use the first service with a browser I'm asked to enter a password. When I enter that I have acces to it but it shows me an 401 error becaus the first service could not acces the second (I belive). So how do I prevent that from happening?
Edit: Fixed Copy paste error(duplicated code)
I think when security is enabled in both services, you need to send the session Id in the header of the rest template call like below,
HttpHeaders requestHeaders = new HttpHeaders();
requestHeaders.add("Cookie", "JSESSIONID=" + session.getValue());
HttpEntity requestEntity = new HttpEntity(null, requestHeaders);
ResponseEntity rssResponse = restTemplate.exchange(
"http://localhost:8090/recommended",
HttpMethod.GET,
requestEntity,
Rss.class);
Rss rss = rssResponse.getBody();`
This may help in making rest template calls between your microservices (This rest template call to be changed accordingly).

Spring Cloud Feign Interceptor

I have created a ClientHttpRequestInterceptor that I use to intercept all outgoing RestTemplate requests and responses. I would like to add the interceptor to all outgoing Feign requests/responses. Is there a way to do this?
I know that there is a feign.RequestInterceptor but with this I can only intercept the request and not the response.
There is a class FeignConfiguration that I found in Github that has the ability to add interceptors but I don't know in which maven dependency version it is.
A practical example of how to intercept the response in a Spring Cloud OpenFeign.
Create a custom Client by extending Client.Default as shown below:
public class CustomFeignClient extends Client.Default {
public CustomFeignClient(SSLSocketFactory sslContextFactory, HostnameVerifier hostnameVerifier) {
super(sslContextFactory, hostnameVerifier);
}
#Override
public Response execute(Request request, Request.Options options) throws IOException {
Response response = super.execute(request, options);
InputStream bodyStream = response.body().asInputStream();
String responseBody = StreamUtils.copyToString(bodyStream, StandardCharsets.UTF_8);
//TODO do whatever you want with the responseBody - parse and modify it
return response.toBuilder().body(responseBody, StandardCharsets.UTF_8).build();
}
}
Then use the custom Client in a configuration class:
public class FeignClientConfig {
public FeignClientConfig() { }
#Bean
public Client client() {
return new CustomFeignClient(null, null);
}
}
Finally, use the configuration class in a FeignClient:
#FeignClient(name = "api-client", url = "${api.base-url}", configuration = FeignClientConfig.class)
public interface ApiClient {
}
Good luck
If you want to use feign from spring cloud, use org.springframework.cloud:spring-cloud-starter-feign as your dependency coordinates. Currently the only way to modify the response is to implement your own feign.Client.

How do I execute a method in Spring when the Server is ready?

I have the following problem: I'm using Spring-Boot for a little private web-based project and I want Spring to make a call to a webservice when it's started. And by started I mean "when my application is ready to handle requests".
I've already tried implementing the ApplicationListener<ContextRefreshedEvent> but it did not work, as the Event happend to early (i.e. before the embedded server was ready to handle request). Also the options mentioned in this question did not solve this problem.
My question now is: Is there any possibilty to tell Spring to execute something after the server has finished starting up and is ready to handle requests?
EDIT (in response to Daniel's answer):
The problem is that I need some injected properties to make that webservice call, and since injecting static values does not work in spring this approach is no option.
My listener, that does what I want, just a bit too early looks something like this:
#Component
public class StartupListener implements ApplicationListener{
#Autowired
private URLProvider urlProvider;
#Value("${server.port}")
private int port;
#Value("${project.name}")
private String projectName;
#Override
public final void onApplicationEvent(ContextRefreshedEvent event) {
RestTemplate template = new RestTemplate();
String url = uriProvider.getWebserviceUrl(this.projectName);
template.put(url, null);
}
}
SECOND EDIT:
Although this question solves a very similar problem it seems like I'm not able to inject into the object because it needs to have a constructor of the form (org.springframework.boot.SpringApplication, [Ljava.lang.String;).
Also it would be desirebale to solve it without having to create the spring.factories file but by using annotations.
If I understand what your problem is, you could call the webservice on your application main, right after it initiates.
public static void main(String[] args) {
new SpringApplication(Application.class).run(args);
//call the webservice for you to handle...
}
I'm not sure if this is what you want...
In your component you can use the #PostConstruct annotation. e.g.
#Component
public class StartupListener {
#Autowired
private URLProvider urlProvider;
#Value("${server.port}")
private int port;
#Value("${project.name}")
private String projectName;
#PostConstruct
public final void init() {
RestTemplate template = new RestTemplate();
String url = uriProvider.getWebserviceUrl(this.projectName);
template.put(url, null);
}
}
This will fire once the bean has been initialised and autowiring has taken place.
#Component
public class StartUp implements ApplicationListener<WebServerInitializedEvent> {
private WebClient webClient;
#Override
public void onApplicationEvent(WebServerInitializedEvent event) {
String baseUrl = "http://url.com"
webClient = WebClient.create(baseUrl);
executeRestCall(baseUrl+"/info");
}
void executeRestCall(String uri) {
try {
webClient.get()
.uri(uri)
.exchange()
.block();
} catch (Exception e) {
log.error("Request failed for url - {}",uri, e);
}
}}

Categories