Mapstruct - манипуляции со строками, но только для одного свойства

Я не уверен, что мне здесь не хватает. Моя настраиваемая логика применяется ко всем атрибутам String, а не только к одному, который я указал для target.

@ApiModel(value="ShopProduct")
@Data
public class ShopProductDTO {
    private String description;
    private String fullImagePath;
}

@Entity
@Table(name = "shop_product")
public class ShopProduct implements Serializable {
    @Column(name = "desc")
    private String description;
    @Column(name = "thumb_path")
    private String thumbPath;
//getters,setters

ImageMapper:

@Component
public class ImagePathMapper {

    AppConfig appConfig;

    public ImagePathMapper(AppConfig appConfig) {
        this.appConfig = appConfig;
    }

    public String toFullImagePath(String thumbPath){
        return appConfig.getImagePath() + thumbPath;
    }
}

ShopProduct Mapper:

@Mapper(componentModel = "spring", uses = {ImagePathMapper.class})
@Component
public interface ShopProductMapper {
    @Mapping(target = "fullImagePath", source = "thumbPath")
    ShopProductDTO shopProductToShopProductDTO(ShopProduct shopProduct);

}

Сгенерированный класс mapstruct:

        ShopProductDTO shopProductDTO = new ShopProductDTO();

        shopProductDTO.setDescription( imagePathMapper.toFullImagePath( shopProduct.getName() ) );

        shopProductDTO.setFullImagePath( imagePathMapper.toFullImagePath( shopProduct.getThumbPath() ) );

}

Почему поле описания также используется с toFullImagePath?

Разве этот @Mapping (target = fullImagePath, source = thumbPath) не должен указывать, что я хочу изменить только fullImagePath?


person Losmi    schedule 03.11.2020    source источник


Ответы (1)


Это не так.

Когда вы определяете сопоставление, Mapstruct будет пытаться сопоставить каждое свойство исходного объекта с целевым объектом в основном на основе соглашения об именах свойств.

Когда вы определяете аннотацию @Mapping, вы указываете исключения для этого базового сопоставления.

В вашем примере, когда вы определяете это:

@Mapping(target = "fullImagePath", source = "thumbPath")

Вы указываете, что свойство thumbPath в исходном объекте должно быть сопоставлено с fullImagePath в целевом объекте: это необходимо, потому что у них разные имена, иначе сопоставление не удастся.

С другой стороны, когда вы определяете атрибут uses=ImagePathMapper.class, вы инструктируете Mapstruct преобразовать каждое свойство, определенное как определенный Class тип, в данном случае String, найденное в исходном объекте: до тех пор, пока все поля, определенные в ShopProduct, String являются этим картографом будет применяться для каждой собственности.

Если вы хотите применить средство сопоставления только для одного поля, вы можете вызвать настраиваемый метод сопоставления или используйте декораторы или до и после сопоставления аннотаций, как в следующем примере:

@Mapper(componentModel = "spring", uses=AppConfig.class, injectionStrategy = InjectionStrategy.CONSTRUCTOR)
public abstract class ShopProductMapper {

  abstract ShopProductDTO shopProductToShopProductDTO(ShopProduct shopProduct);

  @Autowired
  public void setAppConfig(AppConfig appConfig) {
    this.appConfig = appConfig;
  }

  @AfterMapping
  public void toFullImagePath(@MappingTarget ShopProductDTO shopProductDTO, ShopProduct shopProduct) {
    String thumbPath = shopProduct.getThumbPath();
    if (thumbPath != null) {
      shopProductDTO.setFullImagePath(appConfig.getImagePath() + thumbPath);
    }
  }
}

Обратите внимание, что в этом примере вам необходимо внести несколько изменений в свой картограф, чтобы правильно работать с Spring: см. this и это.

person jccampanero    schedule 03.11.2020
comment
Спасибо за подробное объяснение. Работает отлично! - person Losmi; 03.11.2020
comment
Добро пожаловать, Лосми! Я рад услышать, что ответ оказался полезным. - person jccampanero; 03.11.2020
comment
@jccampanero этого также можно достичь с помощью @Named и qualifiedByName для отображения. - person Filip; 04.11.2020
comment
Большое спасибо @Filip, я должен признать, что никогда не использовал его, но он выглядит действительно полезным. Еще раз спасибо, я очень ценю комментарий. - person jccampanero; 04.11.2020