Rest – How to avoid model duplication in JavaEE web applications with a JSON front end

extjsjava-eemvcrest

Recently we developed a web app that uses the following tech stack:

  • hibernate as orm
  • spring
  • extjs (MVC javascript front end)

For 1 business object, let it be a Personnel, we have:

1) a Personnel class (hibernate)
2) PersonnelDTO (will explain why we needed this)
3) a Personnel javascript model for Extjs (I don't know may be other javascript UI frameworks does not need a model defined)

Need for number 2 arised when we couldn't deal with sending hibernate objects back and forth, dealing with sessions and circular references etc. etc.

Plus, in some cases you need a fully filled Personnel object (full fields joined), sometimes just a few fields and a relation. Sometimes you need all the info to process a Personnel but you can't send it all the way to the client (security, privacy reasons). So we used DTO's to decouple model objects and objects that will be sent through the wire.

Adding-removing a field in such a project design becomes very tedious and error prone. Adding a field requires:

  • add to DB tables
  • add to model object
  • add to DTO
  • add to model -> DTO converter (when it's a field that can't be automatically mapped) regarding different scenarios that requires different amount of information about model
  • add to Extjs model
  • add to CRUD forms on the page
  • add to client and server validators…

Isn't there a better approach to building similar applications? We are thinking of starting a new project and don't want to make the same mistakes.

Best Answer

Isn't there a better approach to building similar applications?

I am working on a mid-sized project (150k LoC), with a similar setup:

  • Spring 4
  • OpenJPA for persistence
  • jQuery as the only frontend "framework". I introduced Backbone.JS which is only halfheartedly adopted. A good deal of our application is grid over data, which is implemented via datatables.net.

We are facing similar problems.

In general, there is only little to no help for that. If you are using ORM, you have to use the @Entity-POJOs. If you do not want to expose these objects to the outside, there aren't many options:

1) As you already do: use DTOs - but there is the disadvantage of mapping fields and keeping fields in sync 2) Instantiate a new Domainobject - as said above: @Entities are POJOs and copy over those fields, you want to expose.

Some of our application is grid over data, so there isn't always the need for fully fledged domain objects and sometimes you need a bunch of attributes from several objects. For such cases there is the possibility to work with Constructor expressions in the SELECT clause (see specification). So you could build aggregate-objects (or however you want to name these DTOs) which could span across multiple tables and where each attribute is associated to one column of your resultset. In this case the new object isn't necessarily an @Entity. It has to provide only a constructor which takes all of the columns. (Note to myself: try this out for @Entities).

add to model -> DTO converter (when it's a field that can't be automatically mapped) regarding different scenarios that requires different amount of information about model

This would be best solved via reflection: copy over all fields in the new object from the old one. Done.

The following is highly subjective:

I find ORM isn't the perfect fit for our project. It is a nice to have which frees you from writing tedious boilerplate code, but comes with several downsides: performance trouble (objects involve multiple _LEFT JOIN_s, which you wouldn't need nor make, when writing SQL), too much overhead for simple queries (you get full objects restored instead of just 2 columns or so needed), problems with joins (you are only allowed to join tables, which reflect your models - otherwise, you have to use tricks to get around). If I would start over, I would take a mixed approach: ORM for simple stuff and doing complex stuff with JDBC-templates (our project is currently 100% ORM-Driven).

That said, we now have to take a look at the frontend: Since the advent of MV*-frameworks on the client-side, the question rises, where to put the stress on: client-side vs server-side validation or using both. Here is a nice talk from yeahuda Katz about »the tale of the two MVCs«.

If you go the client-side road, you haven't a duplication of "models", you have client-side-models and "persistence-objects" (@Entities)

To sum it up:

  • some painpoints stay: add to DB tables, add to model object, (add to DTO), add to Extjs model
  • some could be made easy: add to model -> DTO converte (use reflection)
  • you could decide on an either-or-base for some: add to client and server validators

Modern applications are complex.