2016-03-25 1 views
2

今日私は自分のプロジェクト用のModel to DTOコンバータを作成するためにMapStructを使い始めましたが、循環参照を自動的に処理するかどうかは不思議でした。MapStructで変換するときに巡回参照を防止する

これは私がそれをテストするために作られたコンバータです。

package it.cdc.snp.services.rest.giudizio; 

import org.mapstruct.Mapper; 
import org.mapstruct.Mapping; 
import org.mapstruct.Mappings; 
import org.mapstruct.factory.Mappers; 
import org.springframework.stereotype.Component; 

import it.cdc.snp.dto.entita.Avvisinotifica; 
import it.cdc.snp.dto.entita.Corrispondenza; 
import it.cdc.snp.model.notifica.AvvisoDiNotificaModel; 
import it.cdc.snp.model.notifica.NotificaModel; 
import it.cdc.snp.model.procedimento.ProcedimentoModel; 

@Component 
@Mapper(componentModel="spring") 
public interface NotificaMapper { 

    NotificaMapper INSTANCE = Mappers.getMapper(NotificaMapper.class); 

    @Mappings({ 
     @Mapping(source = "avvisinotificas", target = "avvisinotificas"), 
    }) 
    NotificaModel<ProcedimentoModel> corrispondenzaToNotificaModel(Corrispondenza notifica); 

    @Mappings({ 
     @Mapping(source = "corrispondenza", target = "notifica"), 
    }) 
    AvvisoDiNotificaModel avvisinotificaToAvvisoDiNotificaModel(Avvisinotifica avvisinotifica); 


} 

これはテストです:

 Notifica sourceObject1 = new Notifica(); 
     sourceObject1.setId(new Long(1)); 
     Avvisinotifica sourceObject2 = new Avvisinotifica(); 
     sourceObject2.setId(new Long(11)); 
     List<Avvisinotifica> tests= new ArrayList<>(); 
     tests.add(sourceObject2); 
     sourceObject1.setAvvisinotificas(tests); 
     sourceObject2.setCorrispondenza(sourceObject1); 

     NotificaModel destObject1 = new NotificaModel<>(); 
     Avvisinotifica destObject2 = new Avvisinotifica(); 

     NotificaModel converted = mapper.corrispondenzaToNotificaModel(sourceObject1); 

Notifica、Avvisinotificaとそれぞれのモデルはドン私そうセッターとゲッターを持つ単純なPOJOをしていますコードを投稿する必要があると思います(あなたが不思議であれば、NotificaはCorrispondenzaを拡張します)

このコードは無限のサイクルになります。 (私はこれらの状況を処理することを望んだが)。 そして私は手動でそれを扱うエレガントな方法を見つけることができると思うが(私は@MappingTargetとメソッドを使用して参照オブジェクトを挿入することを考えていた)私は循環参照を自動的に処理する方法をMapStructに伝えるいくつかの方法があるかどうか不思議だった。

答えて

3

MapStructでこのようなケースの検出や特別な処理はありませんが、機能要求があります:#469。サイクルにどのように対処するか考えがある場合は、その問題でコメントを削除してください。

+0

は、私は私がやりましたなあ! 1つは、ラッパークラスを使用し、getterが呼び出されたときにその場所で変換することができます。または、問題の作成者が述べたように、既に変換されたアイテムを保持するマップを使用し、変換プロセス中にすでに変換済みのオブジェクトが見つかった場合は、新しいオブジェクトを変換するのではなく、セッターでそのオブジェクトを使用します。しかし、私は実際にそのような提案を容易にするのに十分な専門家ではない – valepu

3

NotificaとAvvisinotificaはあなたのモデルを理解するのに役立っていません。したがって@AfterMappingアノテーション方法は後に、生成されたソース内にインポートされることを意味します

@Mapper 
public abstract class ChildMapper { 

    @AfterMapping 
    protected void ignoreFathersChildren(Child child, @MappingTarget ChildDto childDto) { 
     childDto.getFather().setChildren(null); 
    } 

    public abstract ChildDto myMethod(Child child); 
} 

、あなたがこのようなマッパーを作成する必要があります

public class Child { 
    private int id; 
    private Father father; 
    // Empty constructor and getter/setter methods ommitted. 
} 

public class Father { 
    private int x; 
    private List<Child> children; 
    // Empty constructor and getter/setter methods ommitted. 
} 

public class ChildDto { 
    private int id; 
    private Father father; 
    // Empty constructor and getter/setter methods ommitted. 
} 

public class FatherDto { 
    private int id; 
    private List<Child> children; 
    // Empty constructor and getter/setter methods ommitted. 
} 

、あなたは上記の子供と父親のモデルを持って言うことができますプロパティのマッピングしたがって、Mapperの実装は次のようになります。

@Component 
public class ChildMapperImpl extends ChildMapper { 

    @Override 
    public ChildDto myMethod(Child child) { 
     if (child == null) { 
      return null; 
     } 

     ChildDto childDto = new ChildDto(); 

     childDto.setId(child.getId()); 
     childDto.setFather(child.getFather()); 

     ignoreFathersChildren(child, childDto); 

     return childDto; 
    } 
} 

この実装では、子プロセスに親セットがあります。つまり、サイクルリファレンスが存在することを意味しますが、ignoreFathersChildren(child, childDto)メソッドを使用してリファレンスを削除します(nullに設定します)。

===

更新

方が良いそれを行うことができます1.2.0.Final mapstructのバージョンを使用して、

@Mapper 
public interface ChildMapper { 

    @Mappings({ 
//   @Mapping(target = "father", expression = "java(null)"), 
     @Mapping(target = "father", qualifiedByName = "fatherToFatherDto")}) 
    ChildDto childToChildDto(Child child); 

    @Named("fatherToFatherDto") 
    @Mappings({ 
     @Mapping(target = "children", expression = "java(null)")}) 
    FatherDto fatherToFatherDto(Father father); 
} 
+1

MapStruct 1.2.0.Beta1(昨日リリース)の代替案は、すでにマップされたオブジェクトを追跡するコンテキストパラメータを使用することです。あなたはこれを行う方法を示す完全な例を見つけることができます[ここ](https://github.com/mapstruct/mapstruct-examples/tree/master/mapstruct-mapping-with-cycles/src/main/java/org/mapstruct) /例)。 – Gunnar

関連する問題