Contents
|
This document is a living document! As always read and try out the code to understand what's really going on.
The eJSON project was started by Javier Velilla in 2008. The aim was simply to provide JSON support to Eiffel programmers. A couple of other people have been involved to various extent since the start; Berend de Boer, Jocelyn Fiat and Manu Stapf. In 2009 Paul Cohen joined the project as an active developer.
The formal name of the project is "eJSON".
For questions regarding eJSON please contact <javier.hector at gmail.com> or <paul.cohen at seibostudios.se>
The latest release is 0.2.0. eJSON is still very much in beta status. It has been used in a few applications, but may still be subject to some substantial refactoring and changes to exported classes. We are currently working on the next release 0.3.0 that will consolidate the current code base to a more stable state.
JSON (JavaScript Object Notation) is a lightweight computer data interchange format. It is a text-based, human-readable format for representing simple data structures and associative arrays (called objects). See the Wikipedia article on JSON, www.json.org and www.json.com for more information.
The JSON format is specified in IETF RFC 4627 by Douglas Crockford. The official Internet MIME media type for JSON is "application/json". The recommended file name extension for JSON files is ".json".
1. Lightweight data-interchange format.
2. Easy for humans to read and write.
3. Enables easy integration with AJAX/JavaScript web applications. See the article Speeding Up AJAX with JSON for a good short discussion on this subject.
4. JSON data structures translate with ease into the native data structures universal to almost all programming languages used today.
JSON can be used as a general serialization format for Eiffel objects. As such it could be used as a:
eJSON works today with EiffelStudio 6.5. It also requires the latest snapshot of the Gobo Eiffel libraries (a working snapshot is distributed with EiffelStudio 6.5). The depencencies on Gobo are on Gobo:s unicode and regexp libraries and for some of the extra features in eJSON, on Gobos structure classes DS_HASH_TABLE and DS_LINKED_LIST.
We intend eJSON to work with all ECMA compliant Eiffel compilers.
You can either download a given release and install on your machine or you can get the latest snapshot of the code. To download go to the download page. To get the latest snapshot of the code do:
Here is a list of suggestions for future development of eJSON.
There are two basic approaches to using eJSON; either you use the basic JSON_VALUE classes, converting to and from JSON values to corresponding Eiffel instances or you use the high level eJSON interface class SHARED_EJSON. Of course you can use a mix of both approaches if you find it appropriate!
Here is an example of how to create a JSON number value from an INTEGER and then obtain the JSON representation for that value.
Here is an example of how to do the same using SHARED_EJSON.
The class SHARED_EJSON makes the feature "json" available which is bound to a once instance of EJSON. The use of SHARED_EJSON is typically more motivated when you have more complex Eiffel class instances that you want to convert to/from JSON.
The mappings described here are the default mappings used by eJSON. A user can add custom mappings by subclassing the JSON_CONVERTER class with a custom converter class for a specific type of JSON value and custom Eiffel type value.
First a note on the code examples. As mentioned in the previous chapter you can either work with eJSON by using the JSON_VALUE classes or by non-conforming inheritance of SHARED_EJSON and by using the inherited "json" feature. For sake of brevity the rest of the code examples don't explicitly state the inheritance. You should assume that each code example is in a class that has a declared non-conbforming inheritance clause for SHARED_EJSON.
JSON numbers are represented by the class JSON_NUMBER. JSON number values can be converted to/from NATURAL_*, INTEGER_* and REAL_64 values. For floating point values REAL_* is used. The complete mapping is as follows:
JSON number -> Eiffel:
* -128 <= n <= +127 -> INTEGER_8 * n can't be represented by INTEGER_8 and -32768 <= n <= +32767 -> INTEGER_16 * n can't be represented by INTEGER_16 and -2147483648 <= n <= +2147483647 -> INTEGER_32 * n can't be represented by INTEGER_32 and -9223372036854775808 <= n <= +9223372036854775807 -> INTEGER_64 * n can't be represented by INTEGER_64 and 9223372036854775808 <= n <= 18446744073709551615 -> NATURAL_64 * n has fractional dot '.' -> REAL_64. * n -> eJSON exception if number can't be represented by a INTEGER_64, NATURAL_64 or REAL_64.
Eiffel -> JSON number:
* NATURAL_8, NATURAL_16, NATURAL_32, NATURAL_64, NATURAL -> JSON number * INTEGER_8, INTEGER_16, INTEGER_32, INTEGER_64, INTEGER -> JSON number * REAL_32, REAL_64, REAL -> JSON number
You can use the following creation routines to create JSON_NUMBER instances:
The output of the above code will be:
JSON boolean values are represented by the class JSON_BOOLEAN. The JSON boolean value "true" is converted to/from the BOOLEAN value "True" and the JSON boolean value "false is converted to/from the BOOLEAN value "False".
The output of the above code will be:
JSON strings are represented by the class JSON_STRING. JSON string values can be converted to/from UC_STRING, STRING and CHARACTER values. The complete mapping is as follows:
JSON string -> Eiffel:
* All JSON strings -> UC_STRING
Eiffel -> JSON string:
* UC_STRING -> JSON string * STRING -> JSON string * CHARACTER -> JSON string
The output of the above code will be:
The JSON null value is represented by the class JSON_NULL. The JSON null value can be converted to/from Void.
The output of the above code will be:
JSON array is represented by the class JSON_ARRAY. JSON arrays are by default converted to/from LINKED_LIST, but you can also choose to use Gobo:s DS_LINKED_LIST instead. The conversion will fail if a value of the array is based on a type (or rather base class) for which no default conversion exists and for which no user specified converter is found.
JSON object is represented by the class JSON_OBJECT. JSON objects are by default converted to/from HASH_TABLE [ANY, UC_STRING], but you can choose to use Gobo:s DS_HASH_TABLE instead. The conversion will fail if a value of the hash table is based on a type (or rather base class) for which no default conversion exists and for which no user specified converter is found.
The class EJSON contains the high level client interface to the eJSON library. It contains the three basic features that the typical user of eJSON is interested in:
Using the above features will convert Eiffel objects to/from JSON values as specified by the Eiffel/JSON mapping above. More specifically the two features `object' and `object_from_json' will return Eiffel objects of default types for the given JSON value if the parameter `base_class' is Void. If `base_class' is not Void, the conversion will be to an Eiffel object of a type based on the `base_class' if such a conversion is possible.
In order to ensure the same EJSON instance is shared by all different objects needing to do conversions, you should inherit from SHARED_EJSON (using non-conforming inheritance). You can then access the shared EJSON instance via the `json' feature in SHARED_EJSON.
Important Note: The EJSON features above raise an exception if unable to convert. This solution may be changed in the future to a controlled approach where the features return Void if unable to convert and a query feature is available to query why the conversion failed. However `object' and `object_from_json' will still/also return Void if passed a JSON_NULL object or "null" string respectively!
A client can add conversion support for arbitrary Eiffel classes by subclassing the JSON_CONVERTER class and then registering an instance of your converter with an instance of EJSON. You can of course also write you own custom MY_SHARED_EJSON class that sets up EJSON the way you want.
You can use the SHARED_GOBO_EJSON class instead of SHARED_EJSON if you want to map JSON objects to DS_HASH_TABLE:s instead of HASH_TABLE and JSON arrays to DS_LINKED_LISTS:s instead of LINKED_LIST.
Here is a simple example of how SHARED_EJSON can be used with a custom JSON_FOOBAR_CONVERTER class than can convert between JSON object values and FOOBAR objects (we ignore the exception handling below to keep the example simple).
TBD.
This example require the extension of JSON_NUMBER class with the following features
Output