JUnit 5 with Spring Boot (plus Kotlin)
July 26th, 2016
An overview of new features in JUnit 5 and integrating it into a Spring Boot application written in Kotlin
Recently I had to choose a client to make REST requests from a Grails 2.5 application. I decided to give the Spring RestTemplate a try. It has worked very well, but was missing some functionality that most other clients provide. First off, most clients allow you to set a base URL. This is nice since usually you have a service that builds and configures the client for you. The second was the ability to use Basic Auth. The final piece was to allow for URL parameters to be automatically added to a get request. Thankfully the additional pieces of functionality were easy to add. I have shown what was needed below along with some examples.
The custom rest template that extends RestTemplate and allows for a base path and the automatic addition of url parameters.
import org.springframework.web.client.RequestCallback
import org.springframework.web.client.ResponseExtractor
import org.springframework.web.client.RestClientException
import org.springframework.web.client.RestTemplate
import org.springframework.web.util.UriComponentsBuilder
import org.springframework.web.util.UriTemplate
class CustomRestTemplate extends RestTemplate {
String baseUrl
//allow for the use of a base url
@Override
protected T doExecute(URI url, HttpMethod method, RequestCallback requestCallback, ResponseExtractor responseExtractor) throws RestClientException {
return super.doExecute(new URI(baseUrl + url.toString()), method, requestCallback, responseExtractor)
}
//handle the url expansion our self and if any of the url variables are not in the url add them as a query parameter
@Override
public T execute(String url, HttpMethod method, RequestCallback requestCallback, ResponseExtractor responseExtractor, Map urlVariables) throws RestClientException {
URI expanded = new UriTemplate(url).expand(urlVariables)
UriComponentsBuilder uriComponentsBuilder = UriComponentsBuilder.fromUri(expanded)
urlVariables.each { key, value ->
if(!url.contains("{$key}")) {
if(value instanceof List) {
value.each {
uriComponentsBuilder.queryParam(key, it)
}
} else {
uriComponentsBuilder.queryParam(key, value)
}
}
}
return super.execute(uriComponentsBuilder.toUriString(), method, requestCallback, responseExtractor)
}
}
The interceptor that allows for basic auth.
import org.apache.commons.codec.binary.Base64
import org.springframework.http.HttpHeaders
import org.springframework.http.HttpRequest
import org.springframework.http.client.ClientHttpRequestExecution
import org.springframework.http.client.ClientHttpRequestInterceptor
import org.springframework.http.client.ClientHttpResponse
public class BasicAuthInterceptor implements ClientHttpRequestInterceptor {
private final String username
private final String password
public BasicAuthInterceptor(String username, String password) {
this.username = username
this.password = password
}
//If the basic auth credentials are missing add them to the request header
@Override
public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution ) throws IOException {
HttpHeaders httpHeaders = request.getHeaders()
if(!httpHeaders.containsKey(HttpHeaders.AUTHORIZATION)) {
byte[] userPasswordBytes = (username + ":" + password).bytes
String basicAuth = "Basic " + new String(Base64.encodeBase64(userPasswordBytes))
httpHeaders.set(HttpHeaders.AUTHORIZATION, basicAuth)
}
return execution.execute(request, body)
}
}
An example service that builds our rest template and adds the basic auth interceptor.
import org.springframework.web.client.RestTemplate
class ExampleService {
static transactional = false
def grailsApplication
//returns a rest template that has its base url and basic auth credentials configured
RestTemplate getRestTemplate() {
//Create a rest template with the base url set from a grails config property
def baseUrl = grailsApplication.config.client.api.baseUrl
def template = new CustomRestTemplate(baseUrl: baseUrl)
//add basic auth credentials to the template with an interceptor
def username = grailsApplication.config.client.api.username
def password = grailsApplication.config.client.api.password
def basicAuthInterceptor = new BasicAuthInterceptor(username, password)
template.interceptors = [basicAuthInterceptor]
return template
}
}
The following example now makes a request to http://base-url/object?sort=attribute&order=desc&offset=10&max=10 with the basic auth header included. Notice has the params are just added to the URL.
def restTemplate = exampleService.getRestTemplate()
def params = [sort: "attribute", order: "desc", offset: 10, max: 100]
def jsonObject = restTemplate.getForObject("/object", JSONObject, params)
While this example makes a request to http://base-url/object/1?detail=full with the basic auth header included. This shows we can combine the two methods and use the Spring parameter replacement method, {id}, also.
params = [id: 1, detail: "full"]
jsonObject = restTemplate.getForObject("/object/{id}", JSONObject, params)
An overview of new features in JUnit 5 and integrating it into a Spring Boot application written in Kotlin
Grails 2 has a plugin for Apache Camel called Routing but that plugin hasn’t been upgraded to Grails 3 yet. Luckily, Grails 3 is just Spring Boot so we can use the Camel Spring Boot component … with some caveats. After you add the Camel…
Spring Boot application that sets up a self-contained Graylog instance for event archival and analysis.
Over the years Paul has worked with different technologies including PHP, ASP, Cold Fusion, .Net and numerous content management systems, but he has spent most of his career in the Java world. During that time he has got to work on many web applications including ones for the Marines, Ford, 3M, White Castle, UHG, Canada Dry, Rasmussen College, Lifetime Fitness and TCF Bank.
In recent years he has been focused on Grails applications providing web sites, content management systems and web services. Even though the core of his experience has been server side he has always strived to be a full stack developer. This is becoming increasingly important as front end technologies have transitioned from being mostly visual to now integral parts of an applications functionality.
While out of the office Paul enjoys working on projects around the house, cooking, trying out new foods and beers as well as cheering for the Vikings, Wild and Twins.