DTOs conversion with reflection example - applied on Thymeleaf (or how to get read of Pojo's conversion boilerplate)

I was playing around with Thymeleaf the other day and I wanted to pass all values of my ModelAttribute POJO (Person.class in the example) to Spring's UI Model so I can use the values to the template. (Example to follow).

A form is filled, and the values are passed to a controller that will render them to a new view (html) page. Nothing complex or useful, but just an alternative to hello world if you will.

The ModelAttribute Person.class. Ignore the @ModelElement annotations for now.

The main page that will render a simple form with 1 textfield (name),  one numeric field (age), one drop down menu to restrict the input values of a java enum (sex) and of course the submit button.

When we click the submit button the following controller will be called, passing the values via the Person object. We then are passing them to Spring's model attribute so we can use them to our template. Lines 4-6 should belong in a different class but for simplicity I am putting them in the controller.

The above illustrates the problem. There is a lot of unnecessary code written here. Passing every POJO's field into the model is boring. It generates a lot of boilerplate and its not fun.

Bellow is the Thymeleaf template that will render the attributes of the Person object.

So how do we increase the fun factor here? If we don't mind Reflection (making a conscious choice here), we are going to create a custom annotation (you have already seen it in the Person.class above). We will use it to annotate the fields that we want to pass to the model for rendering in our html template.

The Annotation:
Now we will need a "utility" to take an Object with annotated field and a Model and populate the Model without having to specify every field manually added.
We will use reflection to get all the field of the object (it wont take fields of a super class though), we will use reflection magic to make all accessible and we will check the annotation. If the field is annotated with a key value we will take the key value from the annotation parameter otherwise we will use the field's name as the key.

now we can simply change our controller to something like:

Once again, it is not controller's responsibility to do the parsing (line 3). If we wanted to be SOLID we would have to use a service class, or delegate the parsing to a different object.

Bonus - testing the ModelPopulator (a compact version):


Popular posts from this blog

How to test file operations with Junit5 TempDir

How to create a Cassandra container for testing with Keyspace and the latest schema with a single script call