Category Archives: Articles in English

Spring and string list injection

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.

REST API versioning and hypermedia

Recently, I have been thinking about REST API versioning. I have read several books and articles but the issue is far from straightforward.

Let’s start with a simple example – a petclinic. We will have two resources, pets and owners.

/pets/123  % supports GET, PUT, DELETE
{
   "pet":{
      "name":"Pluto",
      "owner":"/owners/543"
   }
}
/owners/543 % supports GET, PUT, DELETE
{
   "owner":{
      "name":"Norm Ferguson",
      "pets":[
         "/pets/123"
      ]
   }
}

We have a nice and clean REST API. It’s at least level 3 in the Richardson maturity model. Maybe higher.

Our customer is happy, the API is quite popular, but here it comes. A change request. We need to support more owners for a pet. No problem, we can change the resource representation like this.

{
   "pet":{
      "name":"Pluto",
      "owners":[
         "/owners/543"
      ]
   }
}

But it’s a backward incompatible change and we do not want break applications written for the old API. The only option is to create a new version. But how? We have several possibilities.

Version as part of the URI

The Apigee book recommends to add the version to the URI. Something like

/v2/pets/123  % supports GET, PUT, DELETE
{
   "pet":{
      "name":"Pluto",
      "owners":[
         "/owners/543"
      ]
   }
}

You see, I have added version number to the URI. So the clients that support the new API can use v2. But wait, what happens, if a client navigates from v2/pets to owners and back to the pets resource? He will end-up in the first version of the API! We do not want that. It’s inconsistent. To fix this problem, we have to update versions of all resources in our application! The trouble is that we also have to change all the URIs in the resource representations. So the new API would look like this

/v2/pets/123  % supports GET, PUT, DELETE
{
   "pet":{
      "name":"Pluto",
      "owner":"/v2/owners/543"
   }
}
/v2/owners/543 % supports GET, PUT, DELETE
{
   "pet":{
      "name":"Pluto",
      "owners":[
         "/v2/owners/543"
      ]
   }
}

All the resource URI have changed and also all the URIs in the JSON. This change might be easy to implement in a small homogeneous system but will be quite complicated in a system which is composed from several complex modules written in different programming languages. So if you have a REST API which is interconnected by hyperlinks, URI-based versioning will be quite costly. What are the alternatives?

Version as request parameter

/pets/123?v=2
I do not like this one. It’s basically a variant of URI-based versioning. Yes, a client can add the version parameter to every request. But it goes against the notion of hypermedia. The client should not be forced to change the request URI. He should be able to navigate using the links contained in the resource representation.

Version in the header

The other option is to use an HTTP header. The client can pass x-pet-version=2 header with every request and the server will know which version to return. The client usually already uses an HTTP Accept header for content negotiation so one more header should not be a problem. There are several issues with this approach.

The first one is the default value. It’s not clear, what to do, if the client does not send the header. If we serve him the last version, we will break such clients by every API update.

It is also less comfortable to browse older version of such API using the browser.

Version in the domain name

My favorite approach is to use different domain name for each version. Something like http://v2.petclinic.example.org/pets/123. It’s easy to use, easy to implement and easy to change the version. If you use relative URIs, you just need to change the resource that needs to be changed and the rest works automatically. Theoretically, you can even use old code-base on the old domain name and new code-base for the new version.

I am just surprised that this approach is not used more often. If you check popular APIs they usually pick the URI-based approach or HTTP headers. Is there some problem with this approach I do not see?

Sources:

Web API Design: Crafting Interfaces that Developers Love

The REST API Design Handbook

Tomcat throughput (a stupid test)

This week, a colleague of mine had asked me what is the maximal throughput in Tomcat. That he just needs to accept an HTTP request and log the request body. That’s all. How many requests will be handled by Tomcat?

Now stop for a minute and make your guess. Is it
a) 1
b) 10
c) 100
d) 1,000
e) 10,000
f) 100,000

Well, the right answer is that it depends. It depends on your CPU, hard drive, network connection, request size, number of concurrent connections, day of the week and other important factors.

Ok, so I will tell you that I am testing it on an old Lenovo laptop with Intel® Core™2 Duo Processor T8100, 4gigs of RAM and 7200rpm disc, running Linux Mint 11 64bit, Java 6 and Tomcat 7. No performance tuning whatsoever.

I am generating the load from the same machine using JMeter with 50 threads that send requests one after another without any sleep. Each thread sends 20,000 messages containg string “Test ${counter}” where counter goes from 1 to 500,000. Yes, I know that doing tests like this is stupid. Having the test client on the same machine is just wrong. To make it even more stupid, I am writing this article while running the test. On the same old machine, of course.

The data are read from the request reader, stored in a String and sent to Logback to be logged in a file. Nothing fancy. Yes, and I restart the JVM before each test. Another stupid thing. Now you have all the information you need. Make your guess, please.

It turns out that at the and Tomcat is processing ~5,000 request/second. JIT needs some time before it optimizes the code. If I re-execute the test without JVM restart, it gets to ~5,200 requests per second and it does not climb any further. Nice performance. 5,000 request per second.

In my configuration the bottleneck is clearly the CPU. Well, it’s not surprising, JMeter eats half of it. I have also tried to run the test on a MacBook Pro with 8 cores and SSD drive. The throughput is around 22,000 requests per second. Yes, more the 20k requests even in such silly test. On the Mac, JMeter consumes more CPU than Tomcat.

As I have already admitted, my test setup is just wrong. If you want, you may make it better. The source code and the JMeter test are here. It’s just one servlet and few implementation classes, each for different logging strategy (direct, null and using a queue). Feel free to take, change, deploy and test it as you wish. I will be glad to see your results.