2
votes

I'm trying to map a model of a webservice where every List is inside nested object to something more simple.

  1. Model 1
public class Parent {
   private Children children;
}

public class Children {
   private List<Child> children;
}

public class Child {
}
  1. Model 2(simplified)
public class Parent2 {
   private List<Child2> children;
}

public class Child {
}

The mapping is pretty straightforward:

@Mappings({@Mapping(source = "entity.children.children", target = "children")})
Parent2 parentToParent2(Parent entity);
@InheritInverseConfiguration
Parent parent2ToParent(Parent2 entity);

Mapping works fine except for one problem. When I map Parent with null children to Parent2 and back to Parent, the Children object is created with empty list. Is there some way to prevent that?

1
Just tested with 1.2.0.Final and I get Parent having non null Children object with a null children field (Parent.children is non-null, Parent.children.children is null). What would you expect? Parent.children to be null? - jannis
Yes, I'd like exactly that. Because as of now when I map Parent to Parent2 and back, I get different object than what I've started with. - NeplatnyUdaj
hi.. Checkout github.com/mapstruct/mapstruct/issues/1166. Is this what you mean? - Sjaak
Yes, that's exactly it. It looks like it won't be supported in the near future :( - NeplatnyUdaj
It's on my to-do list. But it's a tricky one. I like to have it myself as well. Just need to find time to figure out a decent solution - Sjaak

1 Answers

3
votes

You can achieve that with both a mapper decorator or an AfterMapping hook.

Decorator

Decorator:

public abstract class MapperDecorator implements Mapper {

    private final Mapper delegate;

    public MapperDecorator(Mapper delegate) {
        this.delegate = delegate;
    }

    @Override
    public Parent parent2ToParent(Parent2 entity) {
        Parent parent = delegate.parent2ToParent(entity);

        if (entity.getChildren() == null) {
            parent.setChildren(null);
        }

        return parent;
    }
}

Mapper:

@org.mapstruct.Mapper
@DecoratedWith(MapperDecorator.class)
public interface Mapper {
    @Mapping(source = "entity.children.children", target = "children")
    Parent2 parentToParent2(Parent entity);

    @InheritInverseConfiguration
    Parent parent2ToParent(Parent2 entity);

    Child2 childToChild2(Child entity);

    Child child2ToChild(Child2 entity);
}

AfterMapping

Mapper:

@org.mapstruct.Mapper
public abstract class Mapper {
    @Mapping(source = "entity.children.children", target = "children")
    public abstract Parent2 parentToParent2(Parent entity);

    @InheritInverseConfiguration
    public abstract Parent parent2ToParent(Parent2 entity);

    public abstract Child2 childToChild2(Child entity);

    public abstract Child child2ToChild(Child2 entity);

    @AfterMapping
    public void afterParent2ToParent(Parent2 source,
                                     @MappingTarget Parent target) {
        if (source.getChildren() == null) {
            target.setChildren(null);
        }
    }
}