How to quickly prototype Hibernate or Django model classes from a JSON Object
Tags: django, hibernate, json
Published: 2020-01-18 15:09:54

Despite the plethora of libraries and frameworks I still find It time consuming, error prone and a repetitive work to write model classes for the ORMs I am using in my different projects including **Django model**, **Hibernate**, **Doctrine** or **Room persistence library**. Most of the time they have similar architecture with a set of imports, class definition, annotations, attributes, constructors and getters and setters.

This has led me to think of a way to speed up this process. I started brainstorming and then working on a tool that given a particular JSON object, would generate a code that corresponds to the ORM of interest, a sort of __mapper__, that maps the given JSON object to an ORM tables with its attributes and methods if applicable.

You can [visit the end result here](https://www.p2sdev.com/projects/json-to-orm-converter)

##__The approach__
![Person object](https://res.cloudinary.com/ddfibclzh/image/upload/v1579359405/person_json_bekbhy.png)
<figcaption>Fig.1.1 - A person Object in JSON</figcaption>
The approach was quite simple. Let's consider the JSON in __Fig 1.1__ representing a Person with several attributes. The Person Object is converted into a table with Person as the table’s name and the key-value pairs as the table’s attributes. Below is the JSON object transformed into its Django Model class equivalent.

![person_object_django](https://res.cloudinary.com/ddfibclzh/image/upload/v1579359406/person_django_model_oigwpb.png)
<figcaption>Fig.1.2 - Person Object mapped into its class equivalent in Django Model</figcaption>

We have several exceptions though.
* If we have a JSON Object as an embedded object of another JSON Object as shown in __Fig 1.3__, the embedded JSON Object, in this case Address, will be transformed into another table. A One to One relationship will be set between the two tables which in our example are Person and Address as shown in __Fig 1.4__

```person_id = models.OneToOneField(Person,on_delete=models.CASCADE)```

![person_address_json](https://res.cloudinary.com/ddfibclzh/image/upload/v1579359405/person_address_json_a0mp1t.png)
<figcaption>Fig.1.3 - JSON object with embedded JSON Object</figcaption>
![person_address_django](https://res.cloudinary.com/ddfibclzh/image/upload/v1579359405/person_address_django_peftma.png)
<figcaption>Fig.1.4 - One to One relationship, Django Model</figcaption>

* In the case we have a JSON array as an embedded key-value pair of another JSON Object, and that the value of the JSON array are JSON Object as shown in __Fig 1.5__, the first element of the array is considered and will be transformed into a table, in this case *__visited cities__*. A __Many to One relationship__ will be set between the two tables, in our case __Person__ table and the __Visited cities__ table. __Fig 1.6__ shows the output for the conversion into Django Model

```person_id = models.ForeignKey(Person, on_delete=models.CASCADE)```
![person_list_cities_json](https://res.cloudinary.com/ddfibclzh/image/upload/v1579359406/person_list_cities_kfufyg.png)
<figcaption>Fig.1.5 - A JSON Array embedded in a JSON Object</figcaption>
![person_list_cities_django](https://res.cloudinary.com/ddfibclzh/image/upload/v1579359406/person_list_cities_django_dgatuh.png)
<figcaption>Fig.1.6 - Django Model equivalent of Fig 1.5</figcaption>

* The last exception is when the embedded JSON array is a list of simple data types such as strings, numbers or boolean. The first element will be used to determine the type of that attribute.
![person_list_string_json](https://res.cloudinary.com/ddfibclzh/image/upload/v1579359406/person_list_text_json_r8yyn2.png)
<figcaption>Fig.1.7 - A person with a list of hobbies</figcaption>
![person_list_string_django](https://res.cloudinary.com/ddfibclzh/image/upload/v1579359406/person_list_text_django_hvz6on.png)
<figcaption>Fig.1.8 - The list of hobbies is converted as Character field</figcaption>

##__Supported ORMs__
So far the tool has basic support for Django Model and Hibernate and can also generate SQL create statements for PostgreSQL database. The plan in the near future is to support Doctrine and Room persistence library and be able to generate SQL create statements for MySQL database.

##__Attribute types__
To identify the attribute type to use in our models, the JSON value types are mapped into their corresponding SQL types. We therefore have
* __Boolean__: “false” or false in the JSON value is converted into a Boolean;
* __Numbers__: “23” or 23 in the JSON value is converted into an Integer;
* __Date__: Will mapped string in a format “MM-dd-yyyy” into a Date;
* __String__: if a field is neither a Boolean nor a Number it will be mapped into a String field.

##__Limitations__
* __Field types__: The tool is quite limited to a few attribute types at the moment. Knowing that more fields types are supported by ORMs we tool can evolve to take them into consideration.
* __Relationships__: The same thing applies to relationship between tables. So far only __One To One__ and __Many to One__ relationships are available
* __Other configuration__: Cascade deletion is used by default with One To One and Many To One relationships while there are not always the best choices. The tool should somehow allow users to determine which configuration they want to use.

##__Next steps__
* Take into consideration more attribute types, relationships and configuration
* Generate fixtures using the data passed in the JSON Object

##__Contribution__
You can head to the [GitHub repository](https://github.com/PSteph/jsonToOrmMapper) if you want to contribute to the project or use the [JSON to ORM mapper online tool](https://www.p2sdev.com/projects/json-to-orm-converter).
Thank you for reading till the end, I hope you enjoyed it.