You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何让MapStruct从源对象提取值并返回为目标值?

MapStruct 对象转单个字段值的映射问题

我在用MapStruct时遇到一个问题:MapStruct可以将普通值映射到目标对象的字段中(比如把String转成EmailData对象),但反向操作——从源对象提取单个字段并返回对应类型(比如从EmailData提取email字段返回String)——当前写法无法实现预期效果。

代码示例

1. Mapper接口

import com.example.pixel_user_api.data.entity.EmailData;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;

@Mapper
public interface EmailMapper {
    @Mapping(source = "email", target = ".")
    String toString(EmailData emailData); // 不生效的方法

    @Mapping(source = ".", target = "email")
    EmailData toEmailData(String email); // 正常工作的方法
}

2. 实体类EmailData

import lombok.Getter;
import lombok.Setter;

@Getter
@Setter
public class EmailData {
    private Long id;
    private String email;
}

MapStruct生成的实现代码

@Override
public String toString(EmailData emailData) {
    if ( emailData == null ) {
        return null;
    }

    String string = new String();

    return string;
}

@Override
public EmailData toEmailData(String email) {
    if ( email == null ) {
        return null;
    }

    EmailData emailData = new EmailData();

    emailData.setEmail( email );

    return emailData;
}

可以看到,toString方法只是返回了一个空字符串,没有正确提取emailData的email字段值。

测试代码及失败结果

测试代码

import com.example.pixel_user_api.mapper.EmailMapper;
import org.junit.jupiter.api.Test;
import org.mapstruct.factory.Mappers;

import static org.assertj.core.api.Assertions.assertThat;

class EmailDataTest {
    
    @Test
    void testMapper() {
        String expectedEmail = "example@mail.com";
        EmailData emailData = new EmailData();
        emailData.setEmail(expectedEmail);
        EmailMapper mapper = Mappers.getMapper(EmailMapper.class);
        String actualEmail = mapper.toString(emailData);
        assertThat(actualEmail).isEqualTo(expectedEmail); // 此处断言失败
    }
}

失败结果

org.opentest4j.AssertionFailedError: 
expected: "example@mail.com"
 but was: ""
Expected :"example@mail.com"
Actual   :""

虽然手动实现toString(EmailData)很简单(直接return emailData.getEmail()),但我想知道能否通过MapStruct自动实现这个逻辑?

解决方案

方式1:直接定义方法,无需@Mapping注解

MapStruct会自动识别源对象的getter方法,当方法返回简单类型时,会自动匹配源对象中同类型的属性(如果只有一个同类型属性)。修改Mapper接口如下:

@Mapper
public interface EmailMapper {
    String toString(EmailData emailData); // 自动映射emailData.getEmail()

    @Mapping(source = ".", target = "email")
    EmailData toEmailData(String email);
}

此时MapStruct生成的toString方法会正确提取email字段:

@Override
public String toString(EmailData emailData) {
    if ( emailData == null ) {
        return null;
    }

    String string = emailData.getEmail();

    return string;
}

方式2:使用@Mapping的expression属性(适用于复杂场景)

如果需要添加额外逻辑(比如空值处理、字段转换等),可以用expression属性直接指定代码逻辑:

@Mapper
public interface EmailMapper {
    @Mapping(target = ".", expression = "java(emailData != null ? emailData.getEmail() : \"default@example.com\")")
    String toString(EmailData emailData);

    @Mapping(source = ".", target = "email")
    EmailData toEmailData(String email);
}

这种方式会将表达式中的Java代码直接插入到生成的实现中,灵活性更高。

注意事项

  • 不要使用@Mapping(source = "email", target = ".")这种写法,MapStruct无法正确解析目标为"."的简单类型映射,这是导致原代码失效的原因。
  • 如果源对象中有多个同类型的属性,需要明确指定要提取的字段,此时可以结合@Named注解和@Mapping的qualifiedByName属性来区分。

内容的提问来源于stack exchange,提问作者Sergey Zolotarev

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.13 01:44:54