繁体   English   中英

使用 Guice 从属性文件中注入字符串列表

[英]Injecting a List of Strings From a Properties File Using Guice

我有一个应用程序需要从 Properties 文件中读取一些配置值,然后使用 Guice 的 @Named 注释注入这些值。 我目前正在我的模块中做这样的事情:

@Override
protected void configure() {
    try {
        Properties properties = getProperties();
        Names.bindProperties(binder(), properties);
        binder().bind(MyApi.class);
     } catch (Exception e) {
        log.error(e.getMessage());
        throw new RuntimeException(e);
    }
}

然后在我的应用程序中我做了类似的事情:

public class MyApi
{
    @Inject
    @Named("ftp.dir")
    public String ftpDirectory;
}

这种方法适用于注入原始值,但现在我需要注入一个字符串列表。 如果我只是添加注射

@Inject
@Named("mail.to")
public List<String> mailTo;

对于像这样的属性文件:

#Properties
ftp.dir=/opt/my/dir
mail.to=foo@bar.com, abc@123.com

然后 guice 会抛出一个异常说

'未绑定带有 @google.inject.name.Named(value=mail.to) 注释的 java.util.List<java.lang.String> 的实现'。

我见过一些其他类似的问题,例如: Guice: Inject an ArrayList of Strings和 Injecting list of strings in Guice但所有解决方案都采用为字段添加显式绑定的方法。

有什么方法可以在 guice 中处理 collections 而不必从属性文件中手动提取它们并添加显式绑定?

我设法找到了满足我需求的解决方案。 Guice 3.0 有一种通过 Binder.convertToTypes() 方法添加自定义类型转换器的方法。 我简单地调用了这个方法并传入了 com.google.inject.spi.TypeConverter 的实现,它会获取属性值并将其从字符串转换为列表。 我模块中的配置方法最终看起来像这样:

@Override
protected void configure() {
    try {
        //I'm using apache commons-configurations here but you could
        //just as easily use just a java Properties object
        Configuration properties = getProperties();
 
        //I'm using the builtin Matchers.only from guice for this simple 
        //case but you could implement a custom Matcher for more complex
        //behavior
        binder().convertToTypes(Matchers.only(new TypeLiteral<List<String>>(){}),
     new TypeConverter() {
            //again, I'm using commons-configuration to perform the 
            //actual conversion but you could use a different library
            //or even do the conversion yourself if needed
            final DefaultListDelimiterHandler handler = new DefaultListDelimiterHandler(',');
            @Override
            public Collection<String> convert(String value, TypeLiteral<?> toType) {
                
                return handler.split(value, true);
            }
        });

        //now that guice has a converter registered for List<String>
        //we can simply use bindProperties to set up the Named bindings
        Names.bindProperties(binder(), ConfigurationConverter.getProperties( properties));
        binder().bind(MyApi.class);
    } catch (Exception e) {
        log.error(e.getMessage());
        throw new RuntimeException(e);
    }
}

此解决方案的优势在于它减少了 my.properties 文件与实际代码之间的耦合。 如果我想用 List 值添加额外的属性,我可以简单地更改属性文件,而无需为每个新属性添加自定义提供程序方法。 我的代码和属性文件之间的唯一耦合是在 @Named 注释中。

可能有更好的解决方案; 如果你有什么事请告诉我。 如果要将此问题再开放几天,以防万一有人有更好的建议。

如果将此方法添加到模块中会怎样?

@Named("mail.to") List<String> provideMailtoAsList(@Named("mail.to") String mailto) {
  return List.of(mailto.trim().split("\\s*,\\s*"));
}

这会将名为“mail.to”的已知String转换为恰好也名为“mail.to”的List<String>

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM