I'm trying to convert a ClassDomain class into a ClassEntity but it's not working because it's returning the error below and I don't know how to solve it:
error: The return type List<DomainClass> is an abstract class or interface. Provide a non abstract / non interface result type or a factory method.
Class DataDomainClass:
public class DataDomainClass{
private List<DomainClass> data;
}
Class EntityClass:
public class EntityClass {
private String codDist;
private String numF;
private String textJus;
private Boolean valResol;
}
Convert mapper:
DataDomainClass map(EntityClass entity);
The DomainClass class contains the same fields as the EntityClass class.
Thanks in advance.
CodePudding user response:
MapStruct can't map non-iterable type to iterable, especially mapping non-iterable to a nested collection.
Here's several solutions:
Change method signatures so input and output parameters will be the same type(iterable or non-iterable) and do the wrapping further in code. This is the most preferable solution
Also you can create default method in your interface to do the wrapping there:
@Mapper public interface Entity2DomainMapper { DomainClass entity2Domain(EntityClass raw); default DataDomainClass from(EntityClass raw) { DomainClass nested = entity2Domain(raw); return DataDomainClass.of(List.of(nested)); } }
So instead of calling auto-generated method you'll call default method
Or if you wanna hide all the wrapping inside MapStruct mapper you can use
@AfterMapping
, but it still will require you to implement the wrapping by yourself
@Mapper
public abstract class Entity2DomainMapper2 {
abstract DomainClass entity2Domain(EntityClass raw);
abstract DataDomainClass entity2DataDomain(EntityClass raw);
@AfterMapping
protected void afterMapping(EntityClass raw, @MappingTarget DataDomainClass target) {
if (target.getNested() == null) {
target.setNested(new ArrayList<>());
}
DomainClass nested = entity2Domain(raw);
target.getNested().add(nested);
}
}
CodePudding user response:
There is no clear out-of-box implementation. MapStruct does not support mapping from non-iterable to iterable. Workaround described in mapstruct-examples.
But from my point of view the simples solutions are:
Solution 1: custom method for mapping entity to List
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.factory.Mappers;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@Mapper
public interface DomainMapper {
DomainMapper INSTANCE = Mappers.getMapper(DomainMapper.class);
@Mapping(target = "data", source = "entity")
DataDomainClass map(EntityClass entity);
DomainClass toDomain(EntityClass entity);
default List<DomainClass> toList(EntityClass entity) {
return entity != null ? Collections.singletonList(toDomain(entity)) :
new ArrayList<>();
}
}
Generated code:
public class DomainMapperImpl implements DomainMapper {
@Override
public DataDomainClass map(EntityClass entity) {
if ( entity == null ) {
return null;
}
DataDomainClass dataDomainClass = new DataDomainClass();
dataDomainClass.data = toList( entity );
return dataDomainClass;
}
@Override
public DomainClass toDomain(EntityClass entity) {
if ( entity == null ) {
return null;
}
DomainClass domainClass = new DomainClass();
domainClass.codDist = entity.codDist;
domainClass.numF = entity.numF;
domainClass.textJus = entity.textJus;
domainClass.valResol = entity.valResol;
return domainClass;
}
}
Solution 2: Expression
import org.mapstruct.*;
import org.mapstruct.factory.Mappers;
import java.util.Collections;
@Mapper(imports = {Collections.class})
public interface DomainMapper {
DomainMapper INSTANCE = Mappers.getMapper(DomainMapper.class);
@Mapping(target = "data", expression = "java(Collections.singletonList(toDomain(entity)))")
DataDomainClass map(EntityClass entity);
DomainClass toDomain(EntityClass entity);
}
Generated code:
public class DomainMapperImpl implements DomainMapper {
@Override
public DataDomainClass map(EntityClass entity) {
if ( entity == null ) {
return null;
}
DataDomainClass dataDomainClass = new DataDomainClass();
dataDomainClass.data = Collections.singletonList(toDomain(entity));
return dataDomainClass;
}
@Override
public DomainClass toDomain(EntityClass entity) {
if ( entity == null ) {
return null;
}
DomainClass domainClass = new DomainClass();
domainClass.codDist = entity.codDist;
domainClass.numF = entity.numF;
domainClass.textJus = entity.textJus;
domainClass.valResol = entity.valResol;
return domainClass;
}
}