5

前回の質問のフォローアップのようなものです。JSR-330 標準アノテーションと jersey にバンドルされている HK2 フレームワークを使用して、アプリケーション構成データを挿入しようとしています。

InjectionResolver理想的には、注釈のカスタムを作成したいと思います。これは、またはオブジェクトでNamed必要な値を検索し、他の場所で読み取ったデータから入力します。私の最初の試みでは、次のようなインスタンスを作成しましたMapPropertiesApplication

public class MyApplication extends ResourceConfig {
    ...
    packages(MY_PACKAGES);
    property(MY_CONFIG_PROPERTY, someValue);
    register(new AbstractBinder() {
        @Override
        protected void configure() {
            bind(ConfigurationInjectionResolver.class)
            .to(new TypeLiteral<InjectionResolver<Named>>(){})
            .in(Singleton.class)
        }
    });
}

そして、私のようにInjectionResolver見えます

public class ConfigurationInjectionResolver implements InjectionResolver<Named> {
    @Context Application application;

    @Override
    public Object resolve(Injectee injectee, ServiceHandle<?> serviceHandle) {
        // lookup data in application.getProperties();
    }
}

私の問題はそれapplication.getProperties()が空であることです。何が問題なのですか?また、クラスをバインドする代わりに、インジェクターのインスタンスをバインドできますか? Mapそうすれば、データをパラメーターとして渡すインスタンスを構築できます。

4

1 に答える 1

5

「私の問題は、application.getProperties() が空であることです。何が問題なのですか?

いいえ、これは実際には私にとっては問題なく機能します。

public class ConfigurationInjectionResolver implements InjectionResolver<Named> {  
    @Context
    Application application;

    @Override
    public Object resolve(Injectee injectee, ServiceHandle<?> root) {
        Named annotation = injectee.getParent().getAnnotation(Named.class);
        Map<String, Object> props = application.getProperties();
        String name = annotation.value();
        System.out.println(props.get(name));
        return props.get(name);
    }

    @Override
    public boolean isConstructorParameterIndicator() { return false; }
    @Override
    public boolean isMethodParameterIndicator() { return false; }  
}

@ApplicationPath("/rest")
public class JerseyApplication extends ResourceConfig {

    public JerseyApplication() {
        packages("jersey.startup.test");
        property("hello.config", "Hello World Property");
        register(new AbstractBinder() {
            @Override
            protected void configure() {
                bind(ConfigurationInjectionResolver.class)
                        .to(new TypeLiteral<InjectionResolver<Named>>() {
                        }).in(Singleton.class);
            }
        });
    }
}

リソース

@Path("/config")
public class ConfigResource {

    @Named("hello.config")
    String hello;

    @GET
    public Response getHello() {
        return Response.ok(hello).build();
    }
}

C:\>curl http://localhost:8080/test/rest/config
Hello World Property

個人的には、この状況では、アノテーションの既存の機能をオーバーライドしないように、独自のアノテーションを作成します@Named


別のクールなオプション

HK2 には構成拡張機能があり、Propertiesたとえばファイルからオブジェクトをロードし、.propertiesそれらのプロパティに@Configured注釈を自動的に挿入できます。これに関するドキュメントは見つかりませんでしたが、HK2 source code examplesに使用例があります。

これが実装例です

必要な依存関係。Jersey のバージョンを確認し、依存している HK2 のバージョンを確認します。私の場合、Jersey 2.13 は HK2 2.3.0-b10 を使用するため、それが${hk2.version}

<dependency>
    <groupId>org.glassfish.hk2</groupId>
    <artifactId>hk2-configuration-hub</artifactId>
    <version>${hk2.version}</version>
</dependency>
<dependency>
    <groupId>org.glassfish.hk2</groupId>
    <artifactId>hk2-configuration-integration</artifactId>
    <version>${hk2.version}</version>
</dependency>
<dependency>
    <groupId>org.glassfish.hk2</groupId>
    <artifactId>hk2-property-file</artifactId>
    <version>${hk2.version}</version>
</dependency>

アプリ構成

@ApplicationPath("/rest")
public class JerseyApplication extends ResourceConfig {

    @Inject
    public JerseyApplication(ServiceLocator locator) {
        packages("jersey.startup.test");
        ServiceLocatorUtilities.addClasses(locator, ConfigResource.class);
        try {
            loadConfigurationProperties(locator);
        } catch (IOException ex) {
            Logger.getLogger(JerseyApplication.class.getName())
                                   .log(Level.SEVERE, null, ex);
        }
    }

    private void loadConfigurationProperties(ServiceLocator locator) 
                                                 throws IOException {
        ConfigurationUtilities.enableConfigurationSystem(locator);
        PropertyFileUtilities.enablePropertyFileService(locator);
        PropertyFileService propertyFileService 
                = locator.getService(PropertyFileService.class);
        Properties props = new Properties();
        URL url = getClass().getResource("/configuration.properties");
        props.load(url.openStream());
        PropertyFileHandle propertyFileHandle 
                = propertyFileService.createPropertyHandleOfAnyType();
        propertyFileHandle.readProperties(props);
    }
}

configuration.properties

AppConfiguration.App.hello=Hello Squirrel Property!

リソース

@Path("/config")
@ConfiguredBy("AppConfiguration")
public class ConfigResource {

    @Configured
    String hello;

    @GET
    public Response getHello() {
        return Response.ok(hello).build();
    }
}

C:\>curl http://localhost:8080/test/rest/config
Hello Squirrel Property!

免責事項:この機能は十分に文書化されていないため、ここに適切な実装があるかどうかはわかりません。それは試行錯誤によるものです。たとえば、これ

ServiceLocatorUtilities.addClasses(locator, ConfigResource.class);

必要ないと感じます。私はすでにパッケージをスキャンしているので、冗長に思えます。そのため、ロケーター コンテキストに明示的に追加するConfigResourceことは、私には正しくないようです。

于 2015-01-26T07:09:10.803 に答える