September 1st, 2011
Dnes Dagi narazil v mém kódu na použití třídy java.lang.Void. Řekl jsem si, že se pochlubím i svým věrným čtenářům. Kdyby někdo z vás nevěděl, k čemu taková třída je, můžete si přečíst její JavaDoc.
The Void class is an uninstantiable placeholder class to hold a reference to the Class object representing the Java keyword void.
Jasné jako facka. Pravděpodobně se s tímto typem setkáte při reflexi. Ale mnohem důležitější je použití v generikách. Často totiž narazíte v knihovnách na callbacky, které předpokládají, že chcete vrátit nějakou hodnotu. Například Springovský ConnectionCallback, který vypadá takto
public interface ConnectionCallback<T> {
T doInConnection(Connection con) throws SQLException, DataAccessException;
}
Je ale otázkou jak zvolit typ T, pokud nechcete nic vracet. A zde právě přichází ke slovu java.lang.Void. Můžu napsat například následující kód
template.execute(new ConnectionCallback<Void>() {
@Override
public Void doInConnection(Connection con) {
//your code here
//...
return null;
}
});
Krása nesmírná. Na první pohled je jasné, co se tam děje. Jenom škoda, že musím napsat ten return null.
V rámci objektivity musím přiznat, že to zas není tak důležité. Většinou se s podobným kódem potkáme u anonymních tříd, kde na tom návratovém typu zas tak nezáleží. Ale i tak je to takový pěkný detail, který se hodí znát.
Posted in Uncategorized | No Comments »
August 27th, 2011
Few months ago I have written a small tool that mocks network sockets in Java. Now I have some time to describe it, so here you are.
Let's imagine you want to test network communication in Java. It's not easy, you have to start some server on the other side, configure its responses and somehow verify that the data you send are correct.
With mock-socket it's incredibly easy.
import static net.javacrumbs.mocksocket.MockSocket.*;
...
//prepare mock
byte[] dataToWrite = new byte[]{5,4,3,2};
expectCall().andReturn(emptyResponse());
//do test
Socket socket = SocketFactory.getDefault().createSocket("example.org", 1234);
IOUtils.write(dataToWrite, socket.getOutputStream());
socket.close();
//verify data sent
assertThat(recordedConnections().get(0), data(is(dataToWrite)));
assertThat(recordedConnections().get(0), address(is("example.org:1234")));
You see, just statically import MockSocket class, prepare the mock, execute the test and verify the data. The library just removes the default Java socket implementation and place a mock implementation in its stead.
Of course, this example does not have much sense. It just tests that Java socket implementation works. But imagine that you implement some non-trivial network library. A test library can be handy.
Moreover, there is a HTTP extension which can be used if you want to test some HTTP client. Let's say a JSON REST client. In such case, you can write this.
import static net.javacrumbs.mocksocket.http.HttpMockSocket.*;
...
//prepare mock
expectCall()
.andWhenRequest(uri(is("/test/something.do")))
.thenReturn(response().withStatus(404))
.andWhenRequest(uri(is("/test/other.do")))
.thenReturn(response().withContent("Text")).thenReturn(response().withContent("Text"));
//do your test
...
//verify
assertThat(recordedConnections(), hasItem(header("Accept", is("text/plain"))));
Ain't great? You can do much more, please take a look at the project page if you are interested.
Tags: java, Mock, Socket
Posted in Articles in English, Tests | No Comments »
July 6th, 2011
I have been working on a validation tool that would allow us to validate JSON messages. I could not any usable JSON validator in Java so I have decided to use RelaxNG. It had one catch. RelaxNG is designed for XML validation, not JSON.
That's the reason why I have decided to convert JSON to XML. Before we dive into the implementation, let's think about the problem in general. Both JSON and XML ale tree structures and they are quite similar. In fact, I have discovered only the following differences.
- JSON supports multiple top-level elements. In XML we can have only one root element. While {"a":1, "b":2} is a valid JSON document, <a>1</a><b>2</b> is not valid XML.
- JSON supports arrays, XML does not.
- JSON has null keyword, in XML we several options how to deal with nulls. We can either represent it by an empty element or using xsi:nil attribute.
- JSON has support for boolean and numeric types. In JSON {"a":1} has different meaning than {"a":"1"} (with double quotes). It's not possible to represent such difference in the XML.
All of the problems were acceptable for my needs. There would be more problems when going in the other direction, from XML to JSON, but I did not need it. The only thing I have needed was to convert from
{"root":{
"data1":[
[1,2,3],
[4,5,6]
],
"data2":null,
"data3":"2011-05-30T10:00:00",
"data4":
{
"a":1,
"b":2
}
}
}
to
<?xml version="1.0" encoding="UTF-8"?>
<root>
<data1>
<data1>
<data1>1</data1>
<data1>2</data1>
<data1>3</data1>
</data1>
<data1>
<data1>4</data1>
<data1>5</data1>
<data1>6</data1>
</data1>
</data1>
<data2/>
<data3>2011-05-30T10:00:00</data3>
<data4>
<a>1</a>
<b>2</b>
</data4>
</root>
There already is a project Jettison, that is able to convert between JSON and XML but it does not handle JSON arrays properly. Moreover, I have encountered some bugs like this one. It's trivial to fix but it's there for more than half a year. Strange.
One nice Saturday morning I have decided to implement it. And I have found that it's incredibly easy. It's just matter of using Jackson pull parser and generating SAX events based on it. It's about 200 lines of code that you can enjoy here here.
Tags: JSON, XML
Posted in Articles in English | No Comments »