Reputation: 1
@Data
public class FilesDTO {
private int issue;
private String uniqueStr;
private StorageDomain xml;
private StorageDomain pdf;
private StorageDomain stop;
}
@Data
public class BackHalfDomain {
private int articleId;
private String uniqueStrr;
private long xmlContentId;
private long pdfContentId;
private long stopId;
private int issueNumber;
}
Using a repository class I have to fetch a StorageDomain
object from the ID in BackHalfDomain
. So I have to map StorageDomain
object with respective fields.
like StorgeDomain sd = repo.findById(id).get();
and set this sd
object in FilesDTO
's xml field and so on.
This is my mapper
@Mapper(componentModel = "spring")
public interface FilesDTOMapper {
public static final FilesDTOMapper fileDTOMapper = Mappers.getMapper(FilesDTOMapper.class);
@Mapping(target = "issue", source = "domain.issueNumber")
@Mapping(target = "DOI", source = "domain.doi")
public FilesDTO map(BackHalfDomain domain);
}
I have used uses
but wasn't successful.
I have used @Mapping(target="xyz", expression="java(repo.findById(id))")"
but all I got was NullPointerException
Spring injection isin't working.
Can someone have a solution for this? I am just started with mapstruct
Upvotes: 0
Views: 13833
Reputation: 2223
I ran into this same problem. The solution was to use a Decorator as suggested in this answer. Following your code, the solution would be something like the following.
First, we have to specifiy the Decorator in the Mapper:
@Mapper(componentModel = "spring", unmappedTargetPolicy = ReportingPolicy.IGNORE)
@Primary
@DecoratedWith(FilesDTOMapperDecorator.class)
public interface FilesDTOMapper {
// basic mapping here
public FilesDTO map(BackHalfDomain domain);
}
Then, implement the Decorator:
public abstract class FilesDTOMapperDecorator implements FilesDTOMapper {
@Autowired
@Qualifier("delegate")
private FilesDTOMapper delegate;
@Autowired
private SomeRepository someRepository;
@Override
public FilesDTO map(BackHalfDomain domain) {
// Delegate basic mapping
FilesDTO filesDTO = delegate.map(domain);
// Use the repository as needed to set additional mapping
filesDTO.setSomeValue(repo.findById(id).getSomeValue());
return filesDTO;
}
}
Upvotes: 0
Reputation: 878
Since mapstruct 1.2 you can use a combination of @AfterMapping and @Context.
@Mapper(componentModel="spring")
public interface FilesDTOMapper {
@Mapping(target = "xyz", ignore = true)
@Mapping(target = "issue", source = "domain.issueNumber")
@Mapping(target = "DOI", source = "domain.doi")
FilesDTO map( BackHalfDomain domain, @Context MyRepo repo);
@AfterMapping
default void map( @MappingTarget FilesDTO target, BackHalfDomain domain, @Context MyRepo repo) {
target.setXYZ(repo.findById(domain.getId()));
}
}
In 1.1 you would need to transform the mapper to a abstract class
@Mapper(unmappedTargetPolicy = org.mapstruct.ReportingPolicy.IGNORE,
componentModel = "spring",
uses = {})
public abstract class FilesDTOMapper {
@Autowired
protected MyRepo repo;
@Mapping(target = "issue", source = "domain.issueNumber")
@Mapping(target = "DOI", source = "domain.doi")
@Mapping(target="xyz", expression="java(repo.findById(domain.getId())))")
public FilesDTO map(BackHalfDomain domain);
}
Upvotes: 0