Monday, February 08, 2016

JHipster Entities, JDL and how to regenerate

I have been playing around with jhipster for 1-2 days now to understand how this could help out on some of our projects. Note that I have been using jhipster on Windows 10 , basically pre-requisites is that you have installed the following :
1. npm
2. Java 8
3. maven 3


We have been using spring-boot for quite some time now on a number of different projects
 and jhipster is an interesting framework to consider on top of spring-boot to quickly setup a project which has :

  1. Security already enabled
  2. Domain layer already configured
  3. Basic AngularJS UI in place for CRUD operations
  4. Metrics information
  5. REST api
  6. Swagger integration
  7. Liquidbase integration
  8. and a host other neat features
Now everything really is based on the entities within your domain model . There are different means of Entity generation :

1. through  command line using : yo jhipster:entity NameofYourEntity 
2. or using jhipster-uml

I prefer the jhipster-uml option as its much faster for you to generate your entities rather than having to go through the command line which is error prone and more time consuming.

Assuming that you have installed jhipster properly the first thing you need to do is to install jhipster-uml using the following command :

npm install -g jhipster-uml

Now for jhipster-uml there are a basically 2 fundamental ways to use it either through:

1. UML editors such as Modelio or UML Designers
2. or using the JHipster Domain Language  (JDL)

In our case we are going to use the  JDL because  its agnostic of any UML tooling , faster and you can provide more options e.g pagination which typically you cannot do with the UML tools as they are not specific to jhipster .

1. So first things first create a directory e.g Parking ( am creating a  sample Parking app )

2. Execute yo jhipster on the directory and follow the standard questions depending on what you want  in terms of project name , packing , caching , websockets etc.., this will roughly take a good 3-5 mins to generate a project depending how fast our internet connection is to download everything , am executing this on a Windows Amazon Ec2 instance and its pretty fast 

3. Now we need to create a .jh file in the root folder which will contain our  Entities , their relationships and the options we want enabled. We will call it parking-uml.jh

4. The file content looks like the following, note that the JDL is pretty straightforward: 

-- parking-uml.jh contents-----------

entity ParkingSpace {
  name String required,
  description String  minlength(5) maxlength(50),
  expiration LocalDate
}

enum AvailabilityReason {
    LEAVE, SICK, OUTCOUNTRY, MATERNITY, OTHER
}

entity AvailabilitySlot {
  description String  minlength(5) maxlength(50),
  availabilityReason AvailabilityReason required,
  fromDate ZonedDateTime,
  toDate ZonedDateTime
}

entity BookingSlot {
  description String  minlength(5) maxlength(50),
  fromDate ZonedDateTime,
  toDate ZonedDateTime
}

relationship OneToMany {
  ParkingSpace{availabilitySlots} to AvailabilitySlot{parkingSpace(name)}
}

relationship OneToMany {
  ParkingSpace{bookingSlots} to BookingSlot{parkingSpace(name)}
}

paginate ParkingSpace, AvailabilitySlot, BookingSlot with pagination

service ParkingSpace, AvailabilitySlot, BookingSlot with serviceImpl

------

The documentation page at jhipster-uml already explains the structure of the JDL so i will not go duplicate information from there in this post , however I will explain some of the stuffs to look out for.

The options paginate and  service need to contain all the entities that share the same pagination option on the same line . For example if you wrote them with same option but on different lines for each entitiy then only the BookingSlot will have pagination within the generated AnjularJS pages , ParkingSpace will have no pagination:

paginate ParkingSpace with pagination
paginate BookingSlot with pagination

However if you have different options per entity then you need to have a line per option eg.

paginate ParkingSpace, AvailabilitySlot with pagination
paginate  BookingSlot with infinite-scroll

Also each time you define a relationship create a specific block for that relationship as shown above.

It took me some amount of time to figure this out as was not explicit within the docs.

Now we are ready to generate the Entities , navigate on command line to the root of the directory and execute :

jhipster-uml parking-uml.jh

This will go about generating a number of classes and AngularJS files .

You will see that there is a .jhipster directory which created in your root directory that contains a number of JSON files representing your entities. Do take the time to open the JSON files to  have a look at the generated data.

Running the application is then pretty straight-forward execute on command line:
mvn spring-boot:run
 
This will tell maven to launch an instance of the application typically at http://127.0.0.1:8080/ .

Entities Regeneration

Now the tricky bit is when you need to re-generate your entity classes and I spent hours trying to find the right set of actions so this is what i find works best :

1. update your .jh JDL file in our case its parking-uml.jh with your changes
2. execute a mvn clean this will delete the target directory from all previousy generated classes
3. navigate from within your root directory to src\main\resources\config\liquibase 
4. now edit the master.xml file by removing all the include tags except for  :

<include file="classpath:config/liquibase/changelog/00000000000000_initial_schema.xml" relativeToChangelogFile="false"/>

5. Now go to the changelog sub-directory and delete all xml files except 00000000000000_initial_schema.xml  .

6. We are done with our cleansing , we can regenerate entities using jhipster-uml parking-uml.jh
7. Execute  mvn spring-boot:run to start your app

You should be able to have  now a jhipster app with the updated entities .