AutoFactoryの概要
1. 前書き
このチュートリアルでは、GoogleによるAutoFactoryについて簡単に紹介します。
これは、ファクトリの生成に役立つソースレベルのコードジェネレーターです。
2. Mavenセットアップ
始める前に、次の依存関係をpom.xml:に追加しましょう
com.google.auto.factory
auto-factory
1.0-beta5
最新バージョンはhereで見つけることができます。
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;
}
//...
}
@AutoFactoryと@Providedの2つの注釈のみを使用しました。 クラス用に生成されたファクトリが必要な場合は、@AutoFactory,でアノテーションを付けることができますが、@Providedはこのクラスのコンストラクタパラメータに適用されます。つまり、アノテーションが付けられたパラメータは、注入された%(t4 )s。
上記のスニペットでは、Cameraはすべてのカメラプロデューサーによって提供されると予想され、AutoFactoryは次のコードの生成に役立ちます。
@Generated("com.google.auto.factory.processor.AutoFactoryProcessor")
public final class PhoneFactory {
private final Provider cameraProvider;
@Inject
PhoneAssemblerFactory(Provider 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 java_lang_StringProvider;
@Inject
public ClassicPhoneFactory(Provider 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アノテーションが付けられたパラメータもサポートしますが、JSR-330アノテーションのみがサポートされます。
たとえば、cameraProviderを「Sony」にしたい場合は、Phoneクラスを次のように変更できます。
@AutoFactory
public class Phone {
PhoneAssembler(
@Provided @Named("Sony") Camera camera, String otherParts) {
this.camera = camera;
this.otherParts = otherParts;
}
//...
}
AutoFactoryは@Named@Qualifierを保持するので、たとえば、依存性注入フレームワークを使用するときにそれを利用できます。
@Generated("com.google.auto.factory.processor.AutoFactoryProcessor")
public final class PhoneFactory {
private final Provider cameraProvider;
@Inject
PhoneAssemblerFactory(@Named("Sony") Provider cameraProvider) {
this.cameraProvider = checkNotNull(cameraProvider, 1);
}
//...
}
4. カスタマイズされたコード生成
生成されたコードをカスタマイズするために@AutoFactoryアノテーションで使用できる属性がいくつかあります。
4.1. カスタムクラス名
生成されたファクトリクラスの名前は、classNameで設定できます。
@AutoFactory(className = "SamsungFactory")
public class SmartPhone {
//...
}
上記の構成で、SamsungFactoryという名前のクラスを作成します。
@Generated("com.google.auto.factory.processor.AutoFactoryProcessor")
public final class SamsungFactory {
//...
}
4.2. non-finalファクトリ
生成されたファクトリクラスはデフォルトでfinalとマークされているため、allowSubclasses属性をfalse:に設定することでこの動作を変更できることに注意してください。
@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#L53implementing” parameter.を使用して、生成されたファクトリが実装するインターフェイスのリストを指定できます。
ここでは、カスタマイズ可能なストレージを備えたスマートフォンを製造するためにSamsungFactoryが必要です。
public interface CustomStorage {
SmartPhone customROMInGB(int romSize);
}
インターフェイスのメソッドは、基本クラスSmartPhoneのインスタンスを返す必要があることに注意してください。
Then, to generate a factory class with the interface above implemented, AutoFactory requires relevant constructors in the base class:
@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;
}
}
ここでは、extendingを使用してAbstractFactoryクラスを拡張しました。 また、note that each abstract method in the base abstract class (AbstractFactory) should have a corresponding constructor in the concrete class (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はJSR-330 annotationsをサポートしているため、既存の依存性注入フレームワークを統合できます。
まず、pom.xmlにGuiceを追加しましょう。
com.google.inject
guice
4.2.0
Guiceの最新バージョンはhereにあります。
次に、AutoFactoryがGuiceとどの程度うまく統合されているかを示します。
「Sony」がカメラプロバイダーであることが期待されるため、SonyCameraProviderをPhoneFactoryのコンストラクターに挿入する必要があります。
@Generated("com.google.auto.factory.processor.AutoFactoryProcessor")
public final class PhoneFactory {
private final Provider cameraProvider;
@Inject
public PhoneFactory(@Named("Sony") Provider 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. フードの下
記事で詳細に説明したように、All annotations provided by AutoFactory are processed in the compilation stage:how the source-level annotation processing works.
7. 結論
この記事では、AutoFactoryの使用方法と、AutoFactoryをGuice –書き込みファクトリと統合する方法を紹介しました。繰り返しが発生し、エラーが発生しやすくなります。AutoFactoryやAutoValueなどのコード生成ツールでは多くの時間を節約し、微妙なバグから解放してください。
いつものように、コードサンプルの完全な実装はover on Githubにあります。