javatestngdozer

Usage of Mapping annotation with "this" value (@Mapping("this")) on a field while using github's dozermapper


I came to see a class in which @Mapping("this") was added to a field and a test method which checked that the source object and resulting object are not equal after invoking the map method in github's dozermapper.

As I cannot post the actual code, I am adding a similar class and test method below. (I have used lombok's @Data, @NoArgsConstructor and @AllArgsConstructor annotations to avoid explicitly specifying the getter, setter and constructors.)

@Data
@NoArgsConstructor
@AllArgsConstructor
public class TestObj
{
   private int id;

   @Mapping("this")
   private String name;

}

Test method :

@Test
public void testMapper() {
   TestObj testObj = new TestObj(1, "test");
   TestObj testCopy = DozerBeanMapperBuilder.create().build().map(testObj, TestObj.class);
   Assert.assertNotEquals(testObj, testCopy);
}

The test was passed. If I remove @Mapping("this"), then the same test would fail. So how has the @Mapping("this") changed the mapping procedure so that the mapped object and source object are different?


Solution

  • @Mapping annotation is used when the field names in the source and destination class differ.

    For example, The below code would map the fullName field in the source class object to the name field in the destination class object. This is particularly useful when you are mapping objects of two different classes.

    @Mapping("fullName")
    private int name;
    

    So if we use @Mapping("this") on the name field, then it would map the source class itself to the name field. Here since the name is of type String, the toString() representation of the source class would be mapped to the name field. An exception would be thrown if we have used an incompatible type like int for the name field. The source object itself would have been stored in the name field, if it was of Object type or the same type as the source object.

    So, in the given question, the source and the destination class are the same, but the @Mapping("this") is provided to the name field. So if the source object was like TestObj(id=1,name="test"), then the mapped object would be TestObj(id=1,name="TestObj(id=1,name="test")", i.e the name field would be the toString() of the source object. Hence both the objects would not be equal.

    If the @Mapping("this") is removed, the test would fail because, the @Data annotation adds an equals() method which checks the equality of individual fields and thus the source and mapped object would be equal.