不使用Setter,能否通过MapStruct实现@MappingTarget的相同效果?
无需Setter实现@MappingTarget类似效果的几种方案
针对你不想给实体类添加Setter,又要实现DTO到现有实体的字段更新需求,以下是几种可行方案:
方案1:MapStruct 直接字段访问(推荐)
MapStruct支持直接操作实体类的私有字段,无需依赖Setter方法。只需在Mapper接口中配置相关参数,框架会自动生成反射访问字段的代码。
代码示例
定义Mapper接口:
import org.mapstruct.Mapper; import org.mapstruct.MappingTarget; import org.mapstruct.ReportingPolicy; @Mapper(componentModel = "spring", unmappedTargetPolicy = ReportingPolicy.IGNORE) public interface AdConfigMapper { void updateEntity(AdConfigDto.UpdateDto updateDto, @MappingTarget AdConfigEntity adConfig); }
原理说明
MapStruct生成的实现类会通过反射直接对实体类的私有字段进行赋值,完全不需要Setter方法,既保留了实体类的封装性,又实现了自动映射更新。
方案2:手动字段赋值(完全可控)
如果不想依赖框架,手动编写字段赋值逻辑是最直接的方式,可按需控制更新规则。
同包场景下的直接赋值
若业务方法与实体类处于同一包下,可直接访问包级私有字段(若实体类字段未加private修饰):
public void updateEntity(AdConfigDto.UpdateDto updateDto, AdConfigEntity adConfig) { adConfig.adType = updateDto.getAdType(); adConfig.adCategory = updateDto.getAdCategory(); }
跨包场景下的反射赋值
若实体类字段为私有且跨包,可通过反射绕过访问限制:
import java.lang.reflect.Field; public void updateEntity(AdConfigDto.UpdateDto updateDto, AdConfigEntity adConfig) { try { Field adTypeField = AdConfigEntity.class.getDeclaredField("adType"); adTypeField.setAccessible(true); adTypeField.set(adConfig, updateDto.getAdType()); Field adCategoryField = AdConfigEntity.class.getDeclaredField("adCategory"); adCategoryField.setAccessible(true); adCategoryField.set(adConfig, updateDto.getAdCategory()); } catch (NoSuchFieldException | IllegalAccessException e) { throw new RuntimeException("更新实体字段失败", e); } }
方案3:Builder模式配合MapStruct
给实体类添加Builder支持,MapStruct可利用Builder完成实体更新,无需Setter。
修改实体类添加Builder
使用Lombok的@Builder(toBuilder = true)生成支持从现有实体创建Builder的代码:
import lombok.AllArgsConstructor; import lombok.Builder; import lombok.NoArgsConstructor; import javax.persistence.*; @Entity(name = "ad_config") @Builder(toBuilder = true) @NoArgsConstructor @AllArgsConstructor public class AdConfigEntity extends BaseEntity { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private int adBannerId; private String adBannerTitle; private String adType; private String adCategory; }
配置MapStruct使用Builder
import org.mapstruct.Builder; import org.mapstruct.Mapper; import org.mapstruct.MappingTarget; @Mapper(componentModel = "spring", builder = @Builder(disableBuilder = false)) public interface AdConfigMapper { AdConfigEntity updateEntity(AdConfigDto.UpdateDto updateDto, @MappingTarget AdConfigEntity adConfig); }
原理说明
MapStruct会调用实体的toBuilder()方法创建Builder,替换DTO中的字段后构建出新的实体对象,实现更新效果。
内容的提问来源于stack exchange,提问作者남혁준
相关产品推荐
相关产品推荐

