/collection-json-parser

A library for reading and writing JSON in collection+json format

Primary LanguageJavaMIT LicenseMIT

collection-json-parser

Collection-JSON-parser is a small library for reading and writing JSON in collection+json (from @mamund) format. It was born because I wanted to build a prototype for the office and was in need of pet-project.

The library provides a Java model for Collections, Queries, Tempaltes, Items and Data from Cj. Futhermore it provives a Serializer` which converts any of the above mentioned classes to and from JSON.

For people building a client that uses Cj, the library provides a CjClient which takes care of building requests and parsing responses. Users will need to implement a small HTTPClient which is used by the CjClient to handle communication.

To make building of Collections easier, a set of builders are provided, such as

  • CollectionBuilder
  • DataEntryBuilder and DataEntryFactory
  • ErrorBuilder
  • ItemBuilder
  • LinkBuilder
  • TemplateBuilde

Finally, to convert between Items in a Collection and your domain model, the library makes use of Transformers.

Getting started

There are two ways of getting the library:

Simply clone the repository

git clone https://github.com/felipesere/collection-json-parser.git

and then build it with Maven

maven clean install

Or add the following as a repositry to your pom:

<repositories>
  <repository>
    <id>github-mvn-repo</id>
    <url>https://raw.github.com/felipesere/collection-json-parser/mvn-repo/</url>
    <snapshots>
      <enabled>true</enabled>
      <updatePolicy>always</updatePolicy>
    </snapshots>
  </repository>
</repositories>

Finally, you need to add it as a dependency to your Maven project using the following coordinates

<dependency>
   <groupId>de.fesere.hypermedia</groupId>
   <artifactId>collection-json-parser</artifactId>
   <version>0.0.1-SNAPSHOT</version>
</dependency>

Then you can proceed to create your own Collections or read them from Strings.

Using collection-json-parser to read

The tests in /src/main/test/java mostly show how to use the library.

In a gist, the usage pattern is the following: If you receive a String containing a Collection in JSON, you can serialize it as such:

String json = "{...}";
Serializer serializer = new Serializer();

Collection collection = serializer.deserialize(json, Collection.class);

If you then want to extract the Items and convert them to some domain object, e.g. Foo, you have to implement the ReadTransformer<T> interface and pass it to the convert method:

FooTransformer fooTransformer = new FooTransfomer();
List<Foo> foos = collection.transform(fooTransformer);

The implementation of FooTransformer get each Item of the Collection one at a time. It should use the methods on Item to extract values. The methods are:

  • getString(String name) to get a String value
  • getInt(Stirng name) to get an int
  • getDouble(String name) to get a double
  • getBoolean(String name) to get a boolean
  • getObject(String name) to get the value independent of its type
  • isNullValue(String name) to check whether a value is null (the JSON type)

These methods throw an ElementNotFoundException if no element named name is found and both getInt and getDouble throw a MalformedDataValueException if the value can not be properly converted.

Using collection-json-parser to write

Writing a Collectionis fairly easy. Simply use the differnet builders in de.fesere.hypermedia.cj.model.builder to construct the differnet objects.

For example, if you want to create a Collection with a single Item and two Links, you could the follwing

CollectionBuilder collectionBuilder = new CollectionBuilder(URI.create("http://example.com"));
collectionBuilder.getLinkBuilder().addLink("documentation","/documentation/v1")
                                  .addLink("questions", URI.create("http://stackoverflow.com")).build();

ItemBuilder itemBuilder = new ItemBuilder(URI.create("http;//example.com/item/1"));
itemBuilder.addData(DataEntryFactory.create("name", "Bob", "Users first name"));
itemBuilder.addData(DataEntryFactory.create("age", 24, "Users age"));
itemBuilder.addData(DataEntryFactory.create("height", 0.00192, "Users height in km"));
itemBuilder.addData(DataEntryFactory.create("payed", false, "User payed fee"));

Collection collection = collectionBuilder.addItem(itemBuilder.build()).build();

Serializer serializer = new Serializer();
System.out.println(serializer.serialize(collection));

The DataEntry can be any of

  • StringDataEntry to add String to the data of an entity/template
  • NumberDataEntry to add anything that implements the Java Numberinterface, such as int and double
  • BooleanDataEntry to add a boolean to the item/template
  • NullDataEntry to add an explicit null value to the item/temaplate

You should use the DataEntryFactory method for simplicty. It offers methods for creating regular DataEntry objects, as well as NullDataEntries and EmptyDataEntries. The EmptyDataEntry has a name and possibly a prompt, but no value. It is especially usefull for Templates.

The Java code from above results in

{
    "collection": {
        "version": "1.0",
        "href": "http://example.com",
        "links": [
            {
                "rel": "documentation",
                "href": "http://example.com/documentation/v1"
            },
            {
                "rel": "questions",
                "href": "http://stackoverflow.com"
            }
        ],
        "items": [
            {
                "href": "http;//example.com/item/1",
                "data": [
                    {
                        "name": "name",
                        "value": "Bob",
                        "prompt": "Users first name"
                    },
                    {
                        "name": "age",
                        "value": 24,
                        "prompt": "Users age"
                    },
                    {
                        "name": "height",
                        "value": 0.00192,
                        "prompt": "Users height in km"
                    },
                    {
                        "name": "payed",
                        "value": false,
                        "prompt": "User payed fee"
                    }
                ]
            }
        ]
    }
}

Contributing:

I try to follow the Git flow model by having a master and a develop branch. Please branch from the develop branch and send me pull requests.

Currently there is no differnce between master and develop, but this will change once there are stable releases.

Build status:

Branch Status
Development Build Status
Master: Build Status

Code Coverage:

Coverage Status