1前書き

このチュートリアルでは、Googleによるhttps://github.com/google/auto/tree/master/factory[

AutoFactory

]について簡単に紹介します。

これは、ファクトリの生成に役立つソースレベルのコードジェネレータです。


2 Mavenのセットアップ

始める前に、__pom.xmlに次の依存関係を追加しましょう。

<dependency>
    <groupId>com.google.auto.factory</groupId>
    <artifactId>auto-factory</artifactId>
    <version>1.0-beta5</version>
</dependency>

最新版はhttps://search.maven.org/classic/#search%7Cgav%7C1%7Cg%3A%22com.google.auto.factory%22%20AND%20a%3A%22auto-factory%22にあります。[ここに]。


3クイックスタート

それでは、

AutoFactory

でできることを簡単に見て、単純な

Phone

クラスを作成しましょう。

したがって、

Phone

クラスに

@ AutoFactory

、そのコンストラクタパラメータに

@ Provided

と注釈を付けると、

@AutoFactory
public class Phone {

    private final Camera camera;

    private final String otherParts;

    PhoneAssembler(@Provided Camera camera, String otherParts) {
        this.camera = camera;
        this.otherParts = otherParts;
    }

   //...

}

2つのアノテーションだけを使いました。



@AutoFactory


およびhttps://github.com/google/auto/blob/master/factory/src/main/java/com/google/auto/factory/Provided.java[

@Provided

]。

クラス用に生成されたファクトリが必要なときは、

@ AutoFactory

でアノテーションを付けることができます。一方、

@ Provided

はこのクラスのコンストラクタパラメータに適用されます。 .oracle.com/javaee/6/api/javax/inject/Provider.html[

プロバイダ

]。

上記のスニペットでは、

Camera

が任意のカメラプロデューサーによって提供されることを期待しており、

AutoFactory

は次のコードの生成に役立ちます。

@Generated("com.google.auto.factory.processor.AutoFactoryProcessor")
public final class PhoneFactory {

    private final Provider<Camera> cameraProvider;

    @Inject
    PhoneAssemblerFactory(Provider<Camera> cameraProvider) {
        this.cameraProvider = checkNotNull(cameraProvider, 1);
    }

    PhoneAssembler create(String otherParts) {
      return new PhoneAssembler(
        checkNotNull(cameraProvider.get(), 1),
        checkNotNull(otherParts, 2));
    }

   //...

}

これで、コンパイル時に

AutoFactory

によって自動的に生成された

PhoneFactory

があり、それを使用して電話のインスタンスを生成できます。

PhoneFactory phoneFactory = new PhoneFactory(
  () -> new Camera("Unknown", "XXX"));
Phone simplePhone = phoneFactory.create("other parts");


@ AutoFactory

アノテーションはコンストラクタにも適用できます。

public class ClassicPhone {

    private final String dialpad;
    private final String ringer;
    private String otherParts;

    @AutoFactory
    public ClassicPhone(
      @Provided String dialpad, @Provided String ringer) {
        this.dialpad = dialpad;
        this.ringer = ringer;
    }

    @AutoFactory
    public ClassicPhone(String otherParts) {
        this("defaultDialPad", "defaultRinger");
        this.otherParts = otherParts;
    }

   //...

}

上記のスニペットでは、

@ AutoFactory

を両方のコンストラクタに適用しました。


AutoFactory

は、それに応じて単純に2つの作成メソッドを生成します。

@Generated(value = "com.google.auto.factory.processor.AutoFactoryProcessor")
public final class ClassicPhoneFactory {
    private final Provider<String> java__lang__StringProvider;

    @Inject
    public ClassicPhoneFactory(Provider<String> java__lang__StringProvider) {
        this.java__lang__StringProvider =
          checkNotNull(java__lang__StringProvider, 1);
    }

    public ClassicPhone create() {
        return new ClassicPhone(
          checkNotNull(java__lang__StringProvider.get(), 1),
          checkNotNull(java__lang__StringProvider.get(), 2));
    }

    public ClassicPhone create(String otherParts) {
        return new ClassicPhone(checkNotNull(otherParts, 1));
    }

   //...

}


  • AutoFactory

    は、@ @ Provided__でアノテーションが付けられたパラメータもサポートしますが、これはhttps://jcp.org/en/jsr/detail?id=330[JSR-330]アノテーションのみです。

たとえば、

cameraProvider

を“ Sony”にする場合は、

Phone

クラスを次のように変更します。

@AutoFactory
public class Phone {

    PhoneAssembler(
      @Provided @Named("Sony") Camera camera, String otherParts) {
        this.camera = camera;
        this.otherParts = otherParts;
    }

   //...

}

AutoFactoryはhttps://docs.oracle.com/javaee/6/api/javax/inject/Named.html


https://docs.oracle.com/javaee/6/api/javax/を保持します。

Injection/Qualifier.html[@Qualifier]

これを使用できるようにするには、たとえばDependency Injectionフレームワークを使用する場合などにします。

@Generated("com.google.auto.factory.processor.AutoFactoryProcessor")
public final class PhoneFactory {

    private final Provider<Camera> cameraProvider;

    @Inject
    PhoneAssemblerFactory(@Named("Sony") Provider<Camera> cameraProvider) {
      this.cameraProvider = checkNotNull(cameraProvider, 1);
    }

   //...

}


4カスタマイズされたコード生成

生成コードをカスタマイズするために

@ AutoFactory

アノテーションと共に使用できる属性がいくつかあります。


4.1. カスタムクラス名

生成されたファクトリクラスの名前はhttps://github.com/google/auto/blob/master/factory/src/main/java/com/google/auto/factory/AutoFactory.java#L48[

className

で設定できます。]:

@AutoFactory(className = "SamsungFactory")
public class SmartPhone {

   //...

}

上記の設定で、

SamsungFactory

という名前のクラスを作成します。

@Generated("com.google.auto.factory.processor.AutoFactoryProcessor")
public final class SamsungFactory {

   //...

}


4.2.

非最終

工場

生成されたファクトリクラスはデフォルトでfinalとマークされているので、https://github.com/google/auto/blob/master/factory/src/main/java/com/google/autoを設定することでこの動作を変更できます。

falseの/factory/AutoFactory.java#L64[

allowSubclasses

]属性:

@AutoFactory(
  className = "SamsungFactory",
  allowSubclasses = true)
public class SmartPhone {

   //...

}

今我々は持っています:

@Generated("com.google.auto.factory.processor.AutoFactoryProcessor")
public class SamsungFactory {

   //...

}


4.3. より多くの機能

さらに、https://github.com/google/auto/blob/master/factory/src/main/java/com/google/auto/factory/AutoFactoryを使用して、生成されたファクトリが実装するためのインターフェースのリストを指定できます。 .java#L53[“


_https://github.com/google/auto/blob/master/factory/src/main/java/com/google/auto/factory/AutoFactory.java#L53[implementation」]パラメータ。

_

ここでは、カスタマイズ可能なストレージを持つスマートフォンを製造するための

SamsungFactory

が必要です。

public interface CustomStorage {
    SmartPhone customROMInGB(int romSize);
}

  • インタフェース内のメソッドは、基本クラス

    SmartPhone

    。のインスタンスを返すべきです。

  • 次に、上記のインターフェースを実装したファクトリクラスを生成するために、

    AutoFactory

    は基本クラス内の関連するコンストラクタを必要とします** :

@AutoFactory(
  className = "SamsungFactory",
  allowSubclasses = true,
  implementing = CustomStorage.class)
public class SmartPhone {

    public SmartPhone(int romSize){
       //...
    }

   //...

}

したがって、

AutoFactory

は次のコードを生成します。

@Generated("com.google.auto.factory.processor.AutoFactoryProcessor")
public class SamsungFactory implements CustomStorage {

   //...

    public SmartPhone create(int romSize) {
        return new SmartPhone(romSize);
    }

    @Override
    public SmartPhone customROMInGB(int romSize) {
        return create(romSize);
    }
}


4.4. 拡張子のある工場


AutoFactory

はインターフェースの実装を生成することができるので、クラスを拡張することができると期待するのは当然です。これは確かに可能です:

public abstract class AbstractFactory {
    abstract CustomPhone newInstance(String brand);
}

@AutoFactory(extending = AbstractFactory.class)
public class CustomPhone {

    private final String brand;

    public CustomPhone(String brand) {
        this.brand = brand;
    }
}

ここでは、https://github.com/google/auto/blob/master/factory/src/main/java/com/google/auto/factory/AutoFactory.java#L58[

extending

]を使用して

AbstractFactory

クラスを拡張しました。

また、基本抽象クラス(

AbstractFactory

)内の各抽象メソッドは、具象クラス(

CustomPhone

)内に対応するコンストラクタを持つ必要があります。

最後に、次の生成コードを見ることができます。

@Generated("com.google.auto.factory.processor.AutoFactoryProcessor")
public final class CustomPhoneFactory extends AbstractFactory {

    @Inject
    public CustomPhoneFactory() {
    }

    public CustomPhone create(String brand) {
        return new CustomPhone(checkNotNull(brand, 1));
    }

    @Override
    public CustomPhone newInstance(String brand) {
        return create(brand);
    }

   //...

}


AutoFactory

は、対応する抽象メソッドを実装するためにコンストラクタを利用するのに十分賢いことがわかります –

AutoFactory

のこのような優れた機能は確かに多くの時間とコードを節約します。


5

AutoFactory



Guice


この記事の前半で述べたように、

AutoFactory

はhttps://docs.oracle.com/javaee/6/api/javax/inject/package-summary.html[JSR-330 annotations]をサポートしているため、既存の依存性注入フレームワークを統合できますそれと。

まず、https://github.com/google/guice[

Guice

]を

pom.xml

に追加します。

<dependency>
    <groupId>com.google.inject</groupId>
    <artifactId>guice</artifactId>
    <version>4.2.0</version>
</dependency>


Guice

の最新バージョンはhttps://search.maven.org/classic/#search%7Cgav%7C1%7Cg%3A%22com.google.inject%22%20AND%20a%3A%22guice%22[here]。

それでは、

AutoFactory



Guice

の統合性について説明します。

“ Sony”がカメラプロバイダーになると期待しているので、

PhoneFactory

のコンストラクタに

SonyCameraProvider

をインジェクトする必要があります。

@Generated("com.google.auto.factory.processor.AutoFactoryProcessor")
public final class PhoneFactory {

    private final Provider<Camera> cameraProvider;

    @Inject
    public PhoneFactory(@Named("Sony") Provider<Camera> cameraProvider) {
        this.cameraProvider = checkNotNull(cameraProvider, 1);
    }

   //...

}

最後に、バインディングを

Guice

モジュールに作成します。

public class SonyCameraModule extends AbstractModule {

    private static int SONY__CAMERA__SERIAL = 1;

    @Named("Sony")
    @Provides
    Camera cameraProvider() {
        return new Camera(
          "Sony", String.format("%03d", SONY__CAMERA__SERIAL++));
    }

}

また、

SonyCameraModule



@ Named(“ Sony”)

で注釈を付けたカメラプロバイダーを

PhoneFactory

のコンストラクターパラメーターと一致するように設定しました。

これで、

Guice

が生成されたファクトリの依存性注入を管理していることがわかります。

Injector injector = Guice.createInjector(new SonyCameraModule());
PhoneFactory injectedFactory = injector.getInstance(PhoneFactory.class);
Phone xperia = injectedFactory.create("Xperia");


6. フードの下

記事で詳しく説明したように、

AutoFactory

が提供するすべての注釈はコンパイル段階で処理されます。


7. 結論

この記事では、AutoFactoryの使い方、および

Guiceとの統合方法について説明します。

Aを作成するファクトリは、繰り返しが発生しやすく、エラーが発生しやすくなります。時間を節約し、微妙なバグから解放してください。

いつものように、コードサンプルの完全な実装はhttps://github.com/eugenp/tutorials/tree/master/autovalue[over on Github]にあります。