Я использую MapStruct для передачи данных из одного компонента в другой, и я пытаюсь скопировать данные в неизменяемое внутреннее поле целевого объекта. В частности, внутренним неизменным полем является мультикарта Guava:
// Source.java
import com.google.common.collect.LinkedHashMultimap;
public class Source
{
private final LinkedHashMultimap<String, String> info = LinkedHashMultimap.create();
public LinkedHashMultimap<String, String> getInfo()
{
return info;
}
}
// Target.java
import com.google.common.collect.LinkedHashMultimap;
public class Target
{
private final LinkedHashMultimap<String, String> info = LinkedHashMultimap.create();
public LinkedHashMultimap<String, String> getInfo()
{
return info;
}
}
Основатель c из источника в цель не видит поле info
:
// BasicTargetMapper.java
import org.mapstruct.Mapper;
import org.mapstruct.MappingTarget;
import com.google.common.collect.LinkedHashMultimap;
@Mapper
public interface BasicTargetMapper
{
default void copyMultimap(final LinkedHashMultimap<String, String> sourceMap,
@MappingTarget final LinkedHashMultimap<String, String> targetMap)
{
if (sourceMap != null) {
targetMap.putAll(sourceMap);
}
}
Target toTarget(Source source);
}
// Generated BasicTargetMapperImpl.java
import javax.annotation.Generated;
@Generated(
value = "org.mapstruct.ap.MappingProcessor",
date = "2020-03-10T11:43:53+0100",
comments = "version: 1.3.1.Final, compiler: javac, environment: Java 1.8.0_221 (Oracle Corporation)"
)
public class BasicTargetMapperImpl implements BasicTargetMapper {
@Override
public Target toTarget(Source source) {
if ( source == null ) {
return null;
}
Target target = new Target();
return target;
}
}
Принудительное копирование поля приводит к ошибке компиляции:
// ForcedTargetMapper.java
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.MappingTarget;
import org.mapstruct.Named;
import com.google.common.collect.LinkedHashMultimap;
@Mapper
public interface ForcedTargetMapper
{
@Named("copyMultimap")
default void copyMultimap(final LinkedHashMultimap<String, String> sourceMap,
@MappingTarget final LinkedHashMultimap<String, String> targetMap)
{
if (sourceMap != null) {
targetMap.putAll(sourceMap);
}
}
@Mapping(target = "info", qualifiedByName = "copyMultimap")
Target toTarget(Source source);
}
Компиляция приводит к: Property "info" has no write accessor in Target.
Решение, которое я нашел до сих пор, заключается в использовании @AfterMapping
, как это :
// TargetMapper.java
import org.mapstruct.AfterMapping;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.MappingTarget;
import com.google.common.collect.LinkedHashMultimap;
@Mapper
public interface TargetMapper
{
default void copyMultimap(final LinkedHashMultimap<String, String> sourceMap,
final LinkedHashMultimap<String, String> targetMap)
{
if (sourceMap != null) {
targetMap.putAll(sourceMap);
}
}
@AfterMapping
default void finishCopy(final Source source, @MappingTarget final Target target)
{
copyMultimap(source.getInfo(), target.getInfo());
}
@Mapping(target = "info", ignore = true)
Target toTarget(Source source);
}
// Generated TargetMapperImpl.java
import javax.annotation.Generated;
@Generated(
value = "org.mapstruct.ap.MappingProcessor",
date = "2020-03-10T11:55:42+0100",
comments = "version: 1.3.1.Final, compiler: javac, environment: Java 1.8.0_221 (Oracle Corporation)"
)
public class TargetMapperImpl implements TargetMapper {
@Override
public Target toTarget(Source source) {
if ( source == null ) {
return null;
}
Target target = new Target();
finishCopy( source, target );
return target;
}
}
Есть ли более практичное решение этой проблемы? Тот же вопрос возникает, если целевым полем является постоянная коллекция Hibernate, и вы хотите изменить ее на месте (например: удалить уже сохраненные объекты, обновить существующие и / или добавить новые).