制作自定义@Inject 注释
Making a custom @Inject annotation
我在我的项目中使用 lombok,其中有很多 classes 与 @RequiredArgsConstructors
。我希望在 guice 中自动使用这些构造函数。
一个可行的选择是使用 @RequiredArgsConstructors(onConstructor=@__(@Inject))
但这既丑陋又实验性(阅读:将来可能会从 lombok 中消失)。
我想做的是做一个自定义注入注释,说 @InjectOnlyConstructor
放在我的 class 定义上,并使用 guice's SPIs 来绑定这些类型。但是我不知道如何在 SPI 中发现这些类型。
我如何查看 guice 的元素并绑定到 guice 默认拒绝的这些构造函数?
我希望 class 看起来像的示例:
@Singleton
@InjectOnlyConstructor
@RequiredArgsConstructor
public class CatPictureService {
private final WebServiceClient client;
// Cool stuff that would make facebook cry
}
作为备用计划,我可以有一个模块来扫描我项目的包并自动绑定这些类型。
我开始认为不可能挂接到 Guice 来解析未绑定的类型。
所以我提出了四种不同的解决方案。第一个是我最喜欢的,它包含官方 Guice 扩展使用的看似 显式连接 模式。您按如下方式使用它:
public class Bar {
private Bar(XYZ xyz) { ... }
}
Injector inject = Guice.createInjector(new AbstractModule() {
protected void configure() {
install(new OnlyConstructorBuilder(Bar.class));
}
});
OnlyConstructorBuilder
定义如下:
@RequiredArgsConstructor
private static class OnlyConstructorBuilder extends AbstractModule {
private final Class<?> type;
@Override
protected void configure() {
bindToOnlyConstructor(type);
}
@SuppressWarnings("unchecked")
private <T> void bindToOnlyConstructor(Class<T> type) {
Constructor<T>[] ctors = (Constructor<T>[])type.getDeclaredConstructors();
if (ctors.length > 1) {
addError("%s has too many constructors %s", type.getName(), Arrays.toString(ctors));
return;
} else if (ctors.length < 1) {
addError("%s needs at least one constructor", type.getName());
return;
} else {
bind(type).toConstructor(ctors[0]);
}
}
}
第二种方法是扫描 class 路径(或其中的一部分)以查找特定注释。这是我最初的想法,如果您使用 Guava 的反射助手,这并不难。我以前做过类似的事情,但人们觉得它太神奇了。绑定部分同上。
第三种方法是在模块中 bind(Bar.class)
并使用 Elements SPI 查找带有特定注释的 UntargetedBinding
。但由于我已经绑定了 class,我还不如绑定到唯一的构造函数。
第四种方法是最糟糕的。它使用元素 API 并确定每个绑定的依赖关系;使用特定注释搜索未绑定的依赖项。这是一条我不想走下去的路
我在我的项目中使用 lombok,其中有很多 classes 与 @RequiredArgsConstructors
。我希望在 guice 中自动使用这些构造函数。
一个可行的选择是使用 @RequiredArgsConstructors(onConstructor=@__(@Inject))
但这既丑陋又实验性(阅读:将来可能会从 lombok 中消失)。
我想做的是做一个自定义注入注释,说 @InjectOnlyConstructor
放在我的 class 定义上,并使用 guice's SPIs 来绑定这些类型。但是我不知道如何在 SPI 中发现这些类型。
我如何查看 guice 的元素并绑定到 guice 默认拒绝的这些构造函数?
我希望 class 看起来像的示例:
@Singleton
@InjectOnlyConstructor
@RequiredArgsConstructor
public class CatPictureService {
private final WebServiceClient client;
// Cool stuff that would make facebook cry
}
作为备用计划,我可以有一个模块来扫描我项目的包并自动绑定这些类型。
我开始认为不可能挂接到 Guice 来解析未绑定的类型。
所以我提出了四种不同的解决方案。第一个是我最喜欢的,它包含官方 Guice 扩展使用的看似 显式连接 模式。您按如下方式使用它:
public class Bar {
private Bar(XYZ xyz) { ... }
}
Injector inject = Guice.createInjector(new AbstractModule() {
protected void configure() {
install(new OnlyConstructorBuilder(Bar.class));
}
});
OnlyConstructorBuilder
定义如下:
@RequiredArgsConstructor
private static class OnlyConstructorBuilder extends AbstractModule {
private final Class<?> type;
@Override
protected void configure() {
bindToOnlyConstructor(type);
}
@SuppressWarnings("unchecked")
private <T> void bindToOnlyConstructor(Class<T> type) {
Constructor<T>[] ctors = (Constructor<T>[])type.getDeclaredConstructors();
if (ctors.length > 1) {
addError("%s has too many constructors %s", type.getName(), Arrays.toString(ctors));
return;
} else if (ctors.length < 1) {
addError("%s needs at least one constructor", type.getName());
return;
} else {
bind(type).toConstructor(ctors[0]);
}
}
}
第二种方法是扫描 class 路径(或其中的一部分)以查找特定注释。这是我最初的想法,如果您使用 Guava 的反射助手,这并不难。我以前做过类似的事情,但人们觉得它太神奇了。绑定部分同上。
第三种方法是在模块中 bind(Bar.class)
并使用 Elements SPI 查找带有特定注释的 UntargetedBinding
。但由于我已经绑定了 class,我还不如绑定到唯一的构造函数。
第四种方法是最糟糕的。它使用元素 API 并确定每个绑定的依赖关系;使用特定注释搜索未绑定的依赖项。这是一条我不想走下去的路