Archive for the ‘Spring’ Category

What are ListenableFutures good for?

Tuesday, June 10th, 2014

Standard Futures are in Java since version 5. But recently they started to lose breath. Nowadays we do have asynchronous servlets, asynchronous HTTP clients and lot of other asynchronous libraries. Good old Futures are not good enough for connecting those pieces together.

Let's demonstrate it on a simple example. It's just one of many possible examples, but I think it's the most representative one. Imagine we have a simple servlet controller that just calls some backend API, processes the result and returns it. If you think about it you will notice that we do not need any thread for most of the processing time, we are just waiting for the response. On one end we do have asynchronous servlet and on the other asynchronous HTTP client. We just need to connect those two. In the following example I will be using Spring 4 features, but it's easy to transform it to your favorite library.

@Controller
@EnableAutoConfiguration
public class ListenableFutureAsyncController {
    // Let's use Apache Async HTTP client
    private final AsyncRestTemplate restTemplate = new AsyncRestTemplate(
        new HttpComponentsAsyncClientHttpRequestFactory()
    );

    @RequestMapping("/")
    @ResponseBody
    DeferredResult<String> home() {
        // Create DeferredResult with timeout 5s
        final DeferredResult<String> result = new DeferredResult<>(5000);

        // Let's call the backend
        ListenableFuture<ResponseEntity<String>> future = 
            restTemplate.getForEntity("http://www.google.com", String.class);

        future.addCallback(
          new ListenableFutureCallback<ResponseEntity<String>>() {
            @Override
            public void onSuccess(ResponseEntity<String> response) {
                // Will be called in HttpClient thread
                log("Success");
                result.setResult(response.getBody());
            }

            @Override
            public void onFailure(Throwable t) {
                result.setErrorResult(t.getMessage());
            }
        });
        // Return the thread to servlet container, 
        // the response will be processed by another thread.
        return result;
    }

    public static void log(Object message) {
        System.out.println(format("%s %s ",Thread.currentThread().getName(), message));
    }

    // That's all you need to start the application
    public static void main(String[] args) throws Exception {
        SpringApplication.run(ListenableFutureAsyncController.class, args);
    }
}

The method starts by creating DeferredResult. It's a handy abstraction around asynchronous servlets. If we return DeferredResult, servlet container thread is returned to the pool and another one is later used for sending the result. To send the result, we have to either call setResult or setErrorResult method from another thread.

In the next step we call the backend. We use Spring 4 AsyncRestTemplate which is able to wrap Apache Async HTTP Client. It returns ListenableFuture and we can use callbacks to say what to do when the backend request succeeds or fails. Then it's straightforward to return the result. Please note that the callback is called using HttpClient I/O dispatcher thread. It's fine in our simple case but for more CPU intensive task we would have to use another thread-pool.

The callback is what's important, that's what makes ListenableFutures different. In fact, it's the only difference between Spring ListenableFuture and standard Java 5 future. It's a small difference, but without it we would not be able to implement the example above.

If we write the code like this, we need a thread only for commencing the request and for sending the response back. The rest is handled asynchronously by NIO.

You can also notice that the code is much more complicated than equivalent synchronous code. It's more similar to NodeJS code than to what we are used to in Java. We do have those strange callbacks, different threads processing the same request and other conceptually complicated stuff. So, if you do not need to scale to thousands concurrent requests, you might want to think twice about using this approach. But if you need to scale, this is the direction to go. Next time we will re-implement the same example using Java 8 Completable futures to see if it looks better.

The full source code is available here. It uses Spring Boot so the class you have seen is really all you need.

Spring and string list injection

Saturday, January 12th, 2013

This week, I have been bitten by a surprising behavior of Spring type conversion. Let's have the following bean and Spring config.

public class Bean {
    public void setArray(String[] values) {
        System.out.println("array: " + Arrays.toString(values));
        System.out.println(values.length);
    }

    public void setList(List<String> values) {
        System.out.println("list: " + values);
        System.out.println(values.size());
    }
}
<bean class="net.javacrumbs.Bean">
    <property name="array" value="item1, item2"/>
    <property name="list" value="item1, item2"/>
</bean>

We are trying to inject a String containing comma delimited list of values. The question is whether the String will be automatically converted to list of multiple items in array/list or only one item string will be injected. Both options make sense. What do you think? What will be the length of the array/list? One or two?

The answer is surprising. The array value will be split to two Strings whereas the List will have only one element. The output will be:

array: [item1, item2]
2
list: [item1, item2]
1

It's an easy error to make but hard one to spot. If you log the values, the output is undistinguishable. If you look at the output above, the values are exactly the same. What's worse you usually do not have unit tests to test Spring configuration. In my case the bug got as far as production environment. On test environments we have got only one value in the property so the bug went unnoticed. On the production environment we have set a comma separated list of values. And of course, I have expected the array behavior while using list parameter. Silly me.

WS testing

Tuesday, March 8th, 2011

This post recaps some results of my experiments with WS testing. In last few months I have been working on several projects – Spring WS Test, Spring WS 2.0 testing support and finally on Smock. All of them reflect different approaches to WS testing. Today I am going recapitulate my findings focusing on testing producer/server side code. Consumer/client side will be covered in a following post.

Simple service, simple test

You may wonder what's the problem? Testing web services is easy. We just need to call the endpoint end verify the response. For a simple web service we can write a simple test like this

@Test
public void testPlus()
{
	assertEquals(3, endpoint.plus(1, 2));
}

The test is same as if I was testing a normal method.

Web Services tend to be complex

The trouble is that web services tend to be complex. Normal Java methods usually have few relatively simple parameters. On the other hand, web service request or response could be quite complicated which makes the service endpoint hard to test.

GetFlightsRequest request = new GetFlightsRequest();
request.setFrom("PRG");
request.setTo("DUB");
request.setServiceClass(ServiceClass.BUSINESS);
request.setDepartureDate(DatatypeFactory.newInstance().newXMLGregorianCalendarDate(2011, 02, 23, 0));
//more setter calls could be here
		
GetFlightsResponse response = endpoint.getFlights(request);

List<Flight> flights = response.getFlight();
assertEquals(1, flights.size());
assertEquals(ServiceClass.BUSINESS, flights.get(0).getServiceClass());
//more assertions here

Such tests are bearable only until certain level of complexity. From certain level it's real pain. I really hate to call twenty setters to construct several levels of nested XML hierarchy and then to call dozens of getters to validate the response.

To define XML use ... the XML
The problem is that we want to create or validate an XML structure using wrong language. Java is just not suitable for the task. The best language to describe XML is, surprise, surprise, the XML. Would not it be easier to create XML files containing the request and response and just use them in the test?

GetFlightsRequest request = JAXB.unmarshal(getStream("request1.xml"), GetFlightsRequest.class);
		
GetFlightsResponse response = endpoint.getFlights(request);
		
DOMResult domResponse = new DOMResult();
JAXB.marshal(response, domResponse);
		
XMLUnit.setIgnoreWhitespace(true);
XMLAssert.assertXMLEqual(getDocument("response1.xml"), (Document)domResponse.getNode());

It's much better. This test will look exactly the same way regardless the complexity of the service. But it still have some shortcomings. The biggest one is that usually testing using only one request is not sufficient. I'd like to test the service using different inputs. In such case I have to create lot of XML files that differ just in few elements. It's a maintenance nightmare. If you change the service, you also have to change all the XML files.

Smock comes to help
Up until now we managed to test without any special framework except XMLUnit. Now we will start to use my precious Smock library. The test above can be rewritten to this form.

Map<String, Object> params = new HashMap<String, Object>();
params.put("from", "DUB");
params.put("to", "JFK");
params.put("serviceClass", "economy");
GetFlightsRequest request = createRequest(
					withMessage("request-context-groovy.xml")
					.withParameters(params), GetFlightsRequest.class);

GetFlightsResponse response = endpoint.getFlights(request);

validate(response, request)
	.andExpect(message("response-context-groovy.xml")
	.withParameter("serviceClass", "economy"));

The test is quite similar as the previous one. The difference is that it uses statically imported method createRequest to create a request and validate method to validate the response. The main advantage is that Smock methods support templates. So we can set just values we want to, the rest can be driven by the template. Moreover we do not need to deal with the request structure, parameters can be set into a simple flat map.

<ns1:GetFlightsRequest>
	<ns1:from>${from}</ns1:from>
	<ns1:to>${to}</ns1:to>
	<ns1:departureDate>2001-01-01</ns1:departureDate>
	<ns1:serviceClass>${serviceClass}</ns1:serviceClass>
</ns1:GetFlightsRequest>

Templates are even more useful when comparing the response

<ns3:GetFlightsResponse>
	<ns3:flight>
		<ns2:number>OK1324</ns2:number>
		<ns2:departureTime>2011-02-19T10:00:00</ns2:departureTime>
		<ns2:from>
			<ns2:code>${GetFlightsRequest.from}</ns2:code>
			<ns2:name>${IGNORE}</ns2:name>
			<ns2:city>${IGNORE}</ns2:city>
		</ns2:from>
		<ns2:arrivalTime>2011-02-19T12:00:00</ns2:arrivalTime>
		<ns2:to>
			<ns2:code>${GetFlightsRequest.to}</ns2:code>
			<ns2:name>${IGNORE}</ns2:name>
			<ns2:city>${IGNORE}</ns2:city>
		</ns2:to>
		<ns2:serviceClass>${serviceClass}</ns2:serviceClass>
	</ns3:flight>
</ns3:GetFlightsResponse>

We can ignore some elements, we can compare values based on the request elements and so on. Moreover, when we are using Smock library, we can leverage Spring WS 2.0 testing capabilities that Smock builds on. We can for example validate that the response is valid regarding to its schema.

validate(response).andExpect(validPayload(resource("xsd/messages.xsd")));

Cool, isn't it?

Testing the configuration
Sometimes unit test are not sufficient. Sometimes we want to test the configuration, interceptors, error handling and so on. No problem. If you are using Spring WS 2, you can use the built-in testing library. If you need templates or if you are using different framework like Axis 2, you can use Smock. The test looks similar.

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("file:src/main/webapp/WEB-INF/spring-ws-servlet.xml")
public class GroovyEndpointTest {

	private MockWebServiceClient wsMockClient;
	
	@Autowired
	public void setApplicationContext(ApplicationContext context)
	{
		wsMockClient = createClient(context);
	}
	

	@Test
	public void testResponseTemplate() throws Exception {
		Map<String, Object> params = new HashMap<String, Object>();
		params.put("from", "DUB");
		params.put("to", "JFK");
		params.put("serviceClass", "economy");
		wsMockClient.sendRequest(
			withMessage("request-context-groovy.xml")
			  .withParameters(params))
			.andExpect(message("response-context-groovy.xml")
			  .withParameter("serviceClass", "economy"));
	}

The only difference is that we have to bootstrap the application context. Having done this, we can use the mock web service client to call our services. Even though this kind of tests is more complicated, we can use it to test object-XML mapping, endpoint resolution, error handling and configuration in general.

We have seen several different methods of WS testing. Each of them have advantages and disadvantages. If you keep you services simple, your tests are simple too. If the service is more complex, it makes sense to use XML for the test. Either using your own helper methods, Spring WS 2.0 test support or Smock.

All the samples could be downloaded from here.