2016-08-04 9 views
7

すべてのDTOを生成するのにimmutables frameworkを使用しています。今度は、mapstructを使ってこれらのオブジェクトを互いにマップしたいと思います。しかし生成されたDTOは不変であり、ビルダーパターンに対応するセッターとコンストラクターを持たない。それらは、静的なbuilder()メソッドによってアクセスされる対応するBuilderを介してのみ満たされます。mapstructでビルダー(immutables注釈プロセッサを使用)でオブジェクトを不変オブジェクトにマッピングする

代わりに、mapstructがビルダーのセッターを認識するようにDTO1をDTO2.Builderにマップしようとしましたが、これらは戻り値の型がvoidではなく、流暢な連結のためにBuilder自体を返します。

ここに例のコードを示します。私たちは工場を必要とするビルダーを見つけるためmapstructについては

@Mapper(uses = ObjectFactory.class) 
public interface SourceTargetMapper { 
    SourceTargetMapper MAPPER = Mappers.getMapper(SourceTargetMapper.class); 

    ImmutableMammalEntity.Builder toTarget(MammalDto source); 
} 

は、我々は2つのインタフェース

@Value.Immutable 
public interface MammalDto { 
    public Integer getNumberOfLegs(); 
    public Long getNumberOfStomachs(); 
} 

@Value.Immutable 
public interface MammalEntity { 
    public Long getNumberOfLegs(); 
    public Long getNumberOfStomachs(); 
} 

はその後、我々はmapstructためのマッパー・インターフェースを持っています:

public class ObjectFactory { 

    public ImmutableMammalDto.Builder createMammalDto() { 
    return ImmutableMammalDto.builder(); 
    } 

    public ImmutableMammalEntity.Builder createMammalEntity() { 
    return ImmutableMammalEntity.builder(); 
    } 
} 

コンパイラプラグインは、両方の注釈プロセッサを使用するように指示されたコードを生成するために:

<plugin> 
    <groupId>org.apache.maven.plugins</groupId> 
    <artifactId>maven-compiler-plugin</artifactId> 
    <version>3.6.1</version> 
    <configuration> 
     <source>1.8</source> 
     <target>1.8</target> 
     <annotationProcessorPaths> 
      <path> 
       <groupId>org.immutables</groupId> 
       <artifactId>value</artifactId> 
       <version>2.2.8</version> 
      </path> 
      <path> 
       <groupId>org.mapstruct</groupId> 
       <artifactId>mapstruct-processor</artifactId> 
       <version>1.2.0.Beta3</version> 
      </path> 
     </annotationProcessorPaths> 
    </configuration> 
</plugin> 

注:これはのみ mapstructのバージョンで動作します> 1.2.xでは古いバージョンでは、クリーンビルド(mvn clean compile)で、immutablesが作成したばかりのソースが見つからないという問題があります。 2番目のビルド(クリーンではない)では、注釈プロセッサが実行される前にクラスパス上にあったので、immutablesの実装が見つかります。このバグは修正されました。

これは魅力的です。最初に、インターファクトの不変の実装が生成され、mapstructがそれを使用してビルダーを生成します。

@Test 
public void test() { 
    MammalDto s = ImmutableMammalDto.builder().numberOfLegs(4).numberOfStomachs(3l).build(); 
    MammalEntity t = SourceTargetMapper.MAPPER.toTarget(s).build(); 
    assertThat(t.getNumberOfLegs()).isEqualTo(4); 
    assertThat(t.getNumberOfStomachs()).isEqualTo(3); 
} 

ザ・失敗アサート:

しかし、テストは何のプロパティが設定されていないことを示しています。 mapstructによって生成されたマッパーを見てみると、明らかにセッターが見つかりませんでした。

@Generated(
    value = "org.mapstruct.ap.MappingProcessor", 
    //... 
) 
public class SourceTargetMapperImpl implements SourceTargetMapper { 
    private final ObjectFactory objectFactory = new ObjectFactory(); 

    @Override 
    public Builder toTarget(MammalDto source) { 
     if (source == null) { 
      return null; 
     } 

     Builder builder = objectFactory.createMammalEntity(); 
     return builder; 
    } 
} 

空のビルダーが返されます。私はそれが流暢なAPIを作成するために自分自身を返すための理由が発生したビルダーのセッターの実装だと思う:

public final Builder numberOfLegs(Long numberOfLegs) { 
    this.numberOfLegs = Objects.requireNonNull(numberOfLegs, "numberOfLegs"); 
    return this; 
} 

はmapstructは、これらのセッターを見つけてみましょうする方法はありますか?ビルダーにこのような不変のオブジェクトを扱う良い方法は?

編集:私がコメントに述べたように、私はIssue #782に走った。バージョン1.2.0ではまだビルダーはサポートされていません。しかし、このトピックについてはいくつかの議論があるので、同じ問題がある場合は、その問題に従うのが面白いかもしれません。

+0

私は既知の問題に遭遇したアンドレアスGudianで述べたように、独自のアノテーション

@Value.Style(init = "set*") public @interface SharedData {} 

と、使用中、これらの設定を定義することができます。機能要求#782「ビルダーによる不変オブジェクトのマッピング」は、バージョン1.1.0.Beta2として公開されています。サンプルはmapstructの統合テストモジュールにあります。私は次の反復で特定のニーズにこの慣用句を適応させます。具体的な実施の提案は大歓迎です。 Java-Model-APIはちょっと難しいと思われます... –

答えて

1

私たちのプロジェクトでは同じ問題がありました。 回避策として、私たちは不変なdtoの実装をModifiableで行っています。

また試してみることもできます。ビルダーとオブジェクトファクトリを直接使用する方が良いでしょう。

@Value.Modifiableは、セッターで実装を生成します。

@Value.Style(create = "new")は、パブリックな引数なしのコンストラクタを生成します。

@Value.Immutable 
@Value.Modifiable 
@Value.Style(create = "new") 
public interface MammalEntity { 
    public Long getNumberOfLegs(); 
    public Long getNumberOfStomachs(); 
} 

あなたのマッパーはより簡単になり、オブジェクト工場では必要ありません。

@Mapper 
public interface SourceTargetMapper { 

    ModifiableMammalEntity toTarget(MammalDto source); 
} 

この場合MapStructは、マッパーの意志の使用法は、あなたがビルダーでセッターを生成するImmutablesを設定することができ

// Here you don't need to worry about implementation of MammalEntity is. The interface `MammalEntity` is immutable. 
MammalEntity mammalEntity = sourceTargetMapper.toTarget(source); 
+0

良い点、あなたのアイデアを共有してくれてありがとう!これは、有効なユースケースであるgetter/setter、equals、hashCode、toStringのシンプルコードジェネレータとしてimmutablesを使用する場合に適しています。 (しかし、immutablesは素晴らしいツールです!)しかし、私たちのために、immutablilityはimmutablesフレームワークを選んだ中心的な価値です。私たちはこの利益を犠牲にしたくありません。 –

0

のように見えますModifiableMammalEntity

でセッターを見ることができます:

@Value.Immutable 
@Value.Style(init = "set*") 
public interface MammalEntity { 
    public Long getNumberOfLegs(); 
    public Long getNumberOfStomachs(); 
} 

ObjectBuilderは必要ありません.Generatorを直接使用することもできますerated不変クラス

@Mapper(uses = ImmutableMammalEntity.class) 
public interface SourceTargetMapper { 
    SourceTargetMapper MAPPER = Mappers.getMapper(SourceTargetMapper.class); 

    ImmutableMammalEntity.Builder toTarget(MammalDto source); 
} 

は、あなたも、代わりに

@SharedData 
@Value.Immutable 
public interface MammalEntity { 
    public Long getNumberOfLegs(); 
    public Long getNumberOfStomachs(); 
} 
関連する問題