Conversions

Frequently properties being mapped to each other are represented with values of incompatible types. So we need a way to explicitly define conversion rules.

One of the most common cases is conversion between String and Date values. Nomin provides the solution with predefined the dateFormat conversion which receives a pattern to apply as the only parameter.

  a.strDate = b.details.birth
  dateFormat "dd-MM-yyyy"

There is another useful conversion named simple conversion. It's applicable when we have a limited set of values of the first property corresponding to another set of values of the opposite property. For example, in our case there are boolean value on one side and Gender value on another. So Gender.MALE corresponds true value and Gender.FEMALE corresponds to false. The next snippet shows how one could define such conversion.

  a.gender = b.details.sex
  simple ([Gender.MALE, true], [Gender.FEMALE, false])

  a.stringProperty = b.stringProperty // properties may be instances of the same type
  simple (["A1", "B1"], ["A2", "B2"])

Note, since Nomin 1.1.1 there is overloaded simple method to be more clearer.

  a.gender = b.details.sex
  simple ([a: Gender.MALE, b: true], [a: Gender.FEMALE, b: false])

I think you got the idea :) Please don't confuse the order of elements in pairs, first value is from side a and b is the next.

But it's not all what Nomin provides to you. You are able to define custom conversions using Groovy closures. It's amazing and very powerful feature. You can do anything you desire. No need to create classes, implement interfaces. You place the code performing conversion right there where it's applied.

As the only parameter a closure gets a value that should be converted to an appropriate value for the target property. Let's rewrite the previous conversion using closures.

  a.gender = b.details.sex
  convert to_a: { sex -> sex ? Gender.MALE : Gender.FEMALE }, to_b: { gender -> gender == Gender.MALE }

You can also make expressions more concise using Groovy implicit variable it which refers the only parameter instead of declaring parameter list. To use or not to use it instead of defining the parameter depends on a person's preferences.

  a.gender = b.details.sex
  convert to_a: { it ? Gender.MALE : Gender.FEMALE }, to_b: { it == Gender.MALE }

The next example demonstrates how we can use a service to perform conversions. How to make available services and other components in closures will be discussed more detailed in the rest of this guide. Here you need to know that you can access mapping sides referencing to a and b.

  mappingFor a: Internal, b: External
  a.internalId = b.externalId
  convert to_a: { extId -> idService.resolveExternalId(extId, b) },
  to_b: { intId -> idService.resolveInternalId(intId, a) }

I hope these features help you a lot :)