3

How can I map the following:

class Source {
   String name;
   List<Other> others;
}
class Other {
   String otherName;
   List<More> mores;
}
class More {
   String moreName;
}

class Target {
   String name;
   String otherName;
   String moreName;
}

Hoping it could be something like:

@Mapper
public interface MyMapper {

    @Mapping(target = "name", source = "name")
    @Mapping(target = "otherName", source = "others[0].otherName")
    @Mapping(target = "morename", source = "others[0].mores[0].moreName")
    Target map(Source source);

I see that 'expression = "java(others.get(0).otherName)"' can be used but there are no null checks when using expression, which could result in NullPointeException. Any suggestions with null checks and default can be applied?

2 Answers 2

1

You can use expression to check the null value and return something.

@Mapper
public interface MyMapper {
    @Mapping(target = "name", source = "name")
    @Mapping(target = "otherName", expression = "java(s.others != null && !s.others.isEmpty() ? s.others.get(0).otherName : \"\")")
    @Mapping(target = "moreName", expression = "java(s.others != null && !s.others.isEmpty() && s.others.get(0).mores != null && !s.others.get(0).mores.isEmpty() ? s.others.get(0).mores.get(0).moreName : \"\")")
    Target map(Source s);
}

// mapstruct code generate.
public class MyMapperImpl implements MyMapper {
    @Override
    public Target map(Source s) {
        if ( s == null ) {
            return null;
        }

        Target target = new Target();

        target.name = s.name;

        target.otherName = s.others != null && !s.others.isEmpty() ? s.others.get(0).otherName : "";
        target.moreName = s.others != null && !s.others.isEmpty() && s.others.get(0).mores != null && !s.others.get(0).mores.isEmpty() ? s.others.get(0).mores.get(0).moreName : "";

        return target;
    }
}

If you want readable and reduce the check null duplicate code, you can use the interface default method and use org.springframework.util.ObjectUtils.isEmpty().

@Mapper
public interface MyMapper {
    @Mapping(target = "name", source = "name")
    @Mapping(target = "otherName", expression = "java(getFirstOtherName(s))")
    @Mapping(target = "moreName", expression = "java(getFirstMoreName(s))")
    Target map(Source s);

    default String getFirstOtherName(Source s) {
        return !ObjectUtils.isEmpty(s.others) ? s.others.get(0).otherName : "";
    }

    default String getFirstMoreName(Source s) {
        return !ObjectUtils.isEmpty(s.others) && !ObjectUtils.isEmpty(s.others.get(0).mores) ? s.others.get(0).mores.get(0).moreName : "";
    }
}

// mapstruct code generate.
public class MyMapperImpl implements MyMapper {

    @Override
    public Target map(Source s) {
        if ( s == null ) {
            return null;
        }

        Target target = new Target();

        target.name = s.name;

        target.otherName = getFirstOtherName(s);
        target.moreName = getFirstMoreName(s);

        return target;
    }
} 
Sign up to request clarification or add additional context in comments.

Comments

0

I think you need to see this example: MapStruct String to List mapping

Basically, you need to verify the size of the list before getting some elements.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.