MapStruct使用之万能自定义方法处理

上面的情况都是比较常见、简单的情况,还有更复杂的情况。 比如当字段是null时,可以使用上面的方法处理,但是字段类型String值为"“时,那么该字段不是null就无法适用了。 亦或者,当字段为0或者某些特定值时,需要进行特殊的默认值处理。

上面这些特殊的情况,都可以进行自定义处理。

使用 @BeforeMapping 和 @AfterMapping 进行处理

创建的POJO如下:

@Data  
@Builder  
public class X {  
    private String firstName;  
    private String lastName;  
    private String fullName;  
}
@Data  
@Builder  
public class Y {  
    private String firstName;  
    private String lastName;  
    private String fullName;  
}

映射接口如下:

@Mapper(builder = @Builder(disableBuilder = true))  
public interface XYMapper {  
  
    XYMapper INSTANCE = Mappers.getMapper(XYMapper.class);  
  
    @Mapping(source = "lastName", target = "lastName", defaultValue = "不晓得")  
    Y source2Destination(X x);  
  
    @AfterMapping  
    default void after(@MappingTarget Y y) {  
        if (StringUtils.isBlank(y.getLastName())) {  
            y.setLastName("我是真的不晓得");  
        }  
        if("X".equals(y.getFullName())){  
            y.setFullName("X先生");  
        }  
    }  
  
}

生成的接口实现如下:

public class XYMapperImpl implements XYMapper {  
  
    @Override  
    public Y source2Destination(X x) {  
        if ( x == null ) {  
            return null;  
        }  
  
        String lastName = null;  
        String firstName = null;  
        String fullName = null;  
  
        if ( x.getLastName() != null ) {  
            lastName = x.getLastName();  
        }  
        else {  
            lastName = "不晓得";  
        }  
        firstName = x.getFirstName();  
        fullName = x.getFullName();  
  
        Y y = new Y( firstName, lastName, fullName );  
  
        after( y );  
  
        return y;  
    }  
}

测试如下:

使用空字符串lastName和值为“X”的fullName进行测试:

public class Test {  
  
    public static void main(String[] args) {  
        X x = X.builder().firstName("gg").lastName("").fullName("X").build();  
        System.out.println(x);  
        Y y = XYMapper.INSTANCE.source2Destination(x);  
        System.out.println(y);  
    }  
  
}
X(firstName=gg, lastName=, fullName=X)
Y(firstName=gg, lastName=我是真的不晓得, fullName=X先生)

使用自定义方法加 @QualifiedName 进行处理

创建POJO

@Data  
@Builder  
public class X {  
    private String firstName;  
    private Integer status;  
}
@Data  
@Builder  
public class Y {  
    private String firstName;  
    private String statusName;  
}

编写映射接口

映射接口中,创建一个默认方法 statusConvert 用于将Integer类型的status字段转换成String类型 的StatusName字段,并且给这个方法添加注解 @Nameed(“statusConvert”) 。 然后在 @Mapping 中,使用 qualifiedByName 属性指定上面给定的名称进行绑定。

@Mapper(builder = @Builder(disableBuilder = true))  
public interface XYMapper {  
  
    XYMapper INSTANCE = Mappers.getMapper(XYMapper.class);  
  
    @Mapping(source = "status", target = "statusName", qualifiedByName = "statusConvert")  
    Y source2Destination(X x);  
  
    @Named("statusConvert")  
    default String statusConvert(Integer status) {  
        if (status == null) {  
            return "未知";  
        } else if (status == 1) {  
            return "成功";  
        } else if (status == 2) {  
            return "失败";  
        }  
        return "未知";  
    }  
  
}

接口实现:

public class XYMapperImpl implements XYMapper {  
  
    @Override  
    public Y source2Destination(X x) {  
        if ( x == null ) {  
            return null;  
        }  
  
        String statusName = null;  
        String firstName = null;  
  
        statusName = statusConvert( x.getStatus() );  
        firstName = x.getFirstName();  
  
        Y y = new Y( firstName, statusName );  
  
        return y;  
    }  
}

测试验证

public class Test {  
  
    public static void main(String[] args) {  
        X x = X.builder().firstName("gg").status(1).build();  
        System.out.println(x);  
        Y y = XYMapper.INSTANCE.source2Destination(x);  
        System.out.println(y);  
    }  
  
}
X(firstName=gg, status=1)
Y(firstName=gg, statusName=成功)

使用表达式处理

前面我们已经见过 expression 和 defaultExpression 表达式了,表达式非常强大,既可以返回简单的字符串,也可以调用方法进行处理。

下面简单展示一个调用方法传递参数的例子。

创建POJO

@Data  
@Builder  
public class X {  
    private String firstName;  
    private Integer type;  
}
@Data  
@Builder  
public class Y {  
    private String firstName;  
    private String typeName;  
}

创建外部处理类

public class TypeUtils {  
  
    public static String convert(Integer type) {  
        String typeName = "未知";  
        if (type == null) {  
            return typeName;  
        }  
        switch (type) {  
            case 1:  
                typeName = "飞机";  
                break;  
            case 2:  
                typeName = "大炮";  
                break;  
            case 3:  
                typeName = "坦克";  
                break;  
            case 4:  
                typeName = "潜艇";  
                break;  
            default:  
                break;  
        }  
        return typeName;  
    }  
}

编写映射接口

@Mapper(builder = @Builder(disableBuilder = true))  
public interface XYMapper {  
  
    XYMapper INSTANCE = Mappers.getMapper(XYMapper.class);  
  
    @Mapping(target = "typeName", expression = "java(com.tongde.digitalfabric.incident.test.TypeUtils.convert(x.getType()))")  
    Y source2Destination(X x);  
  
}

生成的接口实现

public class XYMapperImpl implements XYMapper {  
  
    @Override  
    public Y source2Destination(X x) {  
        if ( x == null ) {  
            return null;  
        }  
  
        String firstName = null;  
  
        firstName = x.getFirstName();  
  
        String typeName = com.tongde.digitalfabric.incident.test.TypeUtils.convert(x.getType());  
  
        Y y = new Y( firstName, typeName );  
  
        return y;  
    }  
}

验证测试

public class Test {  
  
    public static void main(String[] args) {  
        X x = X.builder().firstName("gg").type(2).build();  
        System.out.println(x);  
        Y y = XYMapper.INSTANCE.source2Destination(x);  
        System.out.println(y);  
    }  
  
}
X(firstName=gg, type=2)
Y(firstName=gg, typeName=大炮)

最后修改于 2023-08-10