More readable and typeable…
Hamcrest allows you to write readable constraints, which for example can be used with an assert statement. Hamcrest is included since JUnit 4.4 and it is the first time that third-party classes have been included in JUnit. But when you play around with Hamcrest and the assertThat statement you don’t want go back to old complex and unreadable assert statements.
JUnit and assertThat
With Hamcrest it’s very easy to write readable assert statements in a JUnit test case . In the following example we want to check if a person is older than 21 years.
import static org.hamcrest.Matchers.*;
import static org.hamcrest.MatcherAssert.*;
...
Person person1 = new Person();
person1.setName("Bob");
person1.setAge(22);
assertThat(person1.getAge(), greaterThan(21));
As you can see the assert statement is pretty straightforward. The second parameter of an assertThat statement is a Matcher which evaluates if the first parameter is greater than the integer value from the Matcher. This syntax allows you to think in terms of subject, verb, object and not in assertEquals.
Hamcrest uses Matcher which are responsible to evaluate a given statement. A good overview about Hamcrest is the official tutorial.
JUnit currently ships with a few matchers, defined in org.hamcrest.CoreMatchers and org.junit.matchers.JUnitMatchers. To use the other matchers download the hamcrest-all.*.jar library.
hamcrest-collections
hamcrest-collections implements features such as select, reject, map, reduce and zip which can be used on collections. This is a useful library which uses Hamcrest to operate on collections.
The following example show how to select from a List of integers all numbers between 5 and 9.
import static org.hamcrest.Matchers.*;
import static org.hamcrest.MatcherAssert.*;
import static org.hamcrestcollections.Selector.*;
...
List<Integer> numbers = new ArrayList<Integer>();
for (int i = 0; i <= 10; i++) {
numbers.add(i);
}
Iterable<Integer> items = select(numbers, allOf(greaterThan(5), lessThan(9)));
System.out.println(items);
Which genearte the following output:
[6, 7, 8]
Further reading...
A good starting point as already mention is the official Hamcrest Homepage.
JYaml – YAML for Java
“YAML Ain’t Markup Language” (abbreviated YAML) is a data serialization language designed to be human-friendly according to the official Yaml homepage. One implementation for the Java language is the JYaml framework.
There are a lot of other YAML frameworks for different languages. You find a list of some frameworks on the official Yaml homepage.
Short Introduction to YAML
In YAML there are different kinds of nodes:
- Scalar is a value that can be presented as a series of zero or more Unicode characters.
- Sequence is an ordered series of zero or more nodes.
- Mapping is an unordered set of key: value node pairs, with the restriction that each of the keys is unique.
YAML uses three dashes (“- – -”) to show that a document begins. A comment is denoted by a #. In the following sections we now have a look at the YAML constructs sequences, mappings, tags, anchors and aliases.
Sequence
A sequence is a series of nodes, each denoted by a leading “-” indicator.
- Memoirs Found in a Bathtub - Snow Crash - Ghost World
Mapping
A mapping represents a key: value pair.
Stanislaw Lem: Memoirs Found in a Bathtub Neal Stephenson: Snowcrash Daniel Clowes: Ghost World
Tag
YAML represents type information of native data structures with a simple identifier, called a tag (!). The tag serves to restrict the set of possible values the content can have. In this example from JYaml the tag specifies from which type of class the node is.
!my.app.yaml.model.Book
Anchors and Aliases
In the representation graph, a node may appear in more than one collection. An anchor is denoted by the “&” indicator and an alias node by the “*” indicator. The alias refers to the most recent preceding node having the same anchor.
- !my.app.yaml.model.Book
authors:
- &3 !my.app.yaml.model.Author
firstName: Gary
lastName: Michaels
- !my.app.yaml.model.Book
authors:
- !my.app.yaml.model.Author
firstName: Bob
lastName: Jackson
- *3
You find more detail about the YAML standard in the YAML specification.
Note: Some of the examples are from the homepage Yaml In Five Minutes.
JYaml
When you want to serialize and deserialize Java classes with JYaml then all these classes have to obey the following Java beans naming convention.
- The class must have a public default constructor.
- Set/get methods for properties
JYaml currently supports the serialization and deserialization of the following types of Java objects:
- Primitives and respective wrapper classes
- Collection (List and Set)
- Maps
- Arrays
- BigInteger and BigDecimal
- Date
- Custom Java Objects by implementing ObjectsWrappers yourself
JYaml is also in the maven repository. You have just to add the following lines in your pom.xml file.
<dependency> <groupId>org.jyaml</groupId> <artifactId>jyaml</artifactId> <version>1.3</version> </dependency>
Data structure
So we want to serialize and deserialize our data structure which are books and authors. The following line of codes shows you the simple data structure as Java code.
public class Book {
private String isbn;
private String title;
private int pages;
private List<Author> authors = new ArrayList<Author>();
public String getIsbn() {
return isbn;
}
public void setIsbn(String isbn) {
this.isbn = isbn;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public int getPages() {
return pages;
}
public void setPages(int pages) {
this.pages = pages;
}
public List<Author> getAuthors() {
return authors;
}
public void setAuthors(List<Author> authors) {
this.authors = authors;
}
}
public class Author {
private String firstName;
private String lastName;
private Date dateOfBirth;
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public Date getDateOfBirth() {
return dateOfBirth;
}
public void setDateOfBirth(Date dateOfBirth) {
this.dateOfBirth = dateOfBirth;
}
}
Serialize
The serialize step is quite simple all work is done with the static methods from the org.ho.yaml.Yaml class.
List<Book> books = new ArrayList<Book>();
Book book1 = new Book();
book1.setIsbn("123-x");
book1.setTitle("YAML in Action");
book1.setPages(330);
Author author1 = new Author();
author1.setDateOfBirth(new Date());
author1.setFirstName("Gary");
author1.setLastName("Michaels");
book1.getAuthors().add(author1);
books.add(book1);
Book book2 = new Book();
book2.setIsbn("897-x");
book2.setTitle("JYAML for dummies");
book2.setPages(230);
Author author2 = new Author();
author2.setDateOfBirth(new Date());
author2.setFirstName("Bob");
author2.setLastName("Jackson");
book2.getAuthors().add(author2);
book2.getAuthors().add(author1);
books.add(book2);
// write to file
Yaml.dump(books, new File("books.yml"));
The output after the serialization process looks as follow:
---
- !my.app.yaml.model.Book
authors:
- &3 !my.app.yaml.model.Author
dateOfBirth: !java.util.Date "1234212351636"
firstName: Gary
lastName: Michaels
isbn: 123-x
pages: 330
title: YAML in Action
- !my.app.yaml.model.Book
authors:
- !my.app.yaml.model.Author
dateOfBirth: !java.util.Date "1234212351636"
firstName: Bob
lastName: Jackson
- *3
isbn: 897-x
pages: 230
title: JYAML for dummies
Deserialize
To obtain the Java objects from a YAML file you have just to add the following line of code:
List<Book> out = Yaml.loadType(new File("books.yml"), ArrayList.class);