Wednesday, April 27, 2016

JHipster JDL Notes

JDL.  JDL stands for JHipster Domain Language and is a shorthand notation for describing entities and relationships for the jhipster-uml to consume when generating the domain portion of you JHipster code.  My current JHipster learning project quickly evolved to using this format after a few painful sessions with the question and answer approach of the yoeman jhipster:entity sub generator.  The jdl format is pretty concise and allows you to quickly specify the attributes you need to define entities: properties, types, constraints and relationships.

First Issue Encountered.  Once I had my entities defined in JDL and had the generator working to the point where I had working CRUD for all my entities, I started playing with the functionality.   The first thing I noticed was that all of the entities that had relationships to others (let's say children entities) would always represent the child as the Primary Key ID value of the object.  To illustrate I'll use the example of an Employee - Department relationship where an department has many employees.  When listing the employee, JHipster would show all of the attributes of the employee (name, position, years employed) and then show the numeric id (Primary Key) of the department.  Not a very good user experience.  Of course what I wanted was the department name, both in the listings of the employee and as a drop down selection when editing a single employee.  

First Issue Solved. It makes sense that JHipster used the department id as the data showing the relationship.  After all, I did not tell it WHICH piece of data in the department object would be meaningful (and unique) to the user.  Thankfully the the JDL has a nice facility to not only indicate the relationship between entities, but also indicate the field which would be meaningful to the user, and thus be used to represent the relationship on the parent object when used in the UI. My original relationship section of my JDL looked like this:

relationship ManyToOne {
    Employee {worksInDept} to Department
This defines that there are many employees in a department and that the employee entity will contain a property named worksInDept that will be the child department object.  When the relationship is defined like this, JHipster simply defaults to using the department id in representing department in any employee UI areas.  In order to tell JHipster that the property on the department object to be used, I had to make the following change:

relationship ManyToOne {
    Employee {worksInDept(deptName)} to Department

Note the add of the deptName property.  Not sure what this construct is actually called in JDL.  It shows up in one of their examples but is not documented in the relationship declaration definition:

relationship (OneToMany | ManyToOne | OneToOne | ManyToMany) {
  <from entity>[{<relationship name>}] to <to entity>[{<relationship name>}]

Second Issue Encountered. So the addition of the unnamed attribute in JDL seemed to have solved my first issue. The generated code included additional references in the EmployeeDTO to the new deptName property called worksInDeptDeptName and appeared to use it through to the angular display of employees (lists, edit, etc). However when I ran the app, the mapper did not map the new field on the DTO. It left it null. The EmployeeMapper clearly had a mapping annotation to pull the from the related worksInDept object and put it in worksInDeptDeptName, but it wasn't doing it at run time.

Second Issue Solved. My first thought was that the mapping library was broken. My second thought was that there is no way that wouldn't get fixed before I see it in release. I then started looking at the MapStruct lib and learned that it does its mapping magic by generating code for the mappers at compile time. I happened to be running my code in Intellij from its Spring Boot run configuration and I pretty quickly guessed that it was bypassing the code generation that the Gradle build was doing. I ran the Gradle build and the mappers worked. No more nulls and I get the user friendly department name throughout the Employee UI facilities.

Next Up.  One of my big frustrations with code generation approaches is how to add code and not break the upgrade path.  When a new JHipster version comes out, I have a laborious set of tasks to restore my custom adds (homepage, ssl, etc) after re-running the code generation.  I'll start to think about how to deal with this and write up my findings as I arrive at them.

No comments: