web-dev-qa-db-ja.com

UnsatisfiedDependencyException:SystemInjecteeImplで注入可能なオブジェクトがありませんでした

Jersey RestアプリケーションでDIを使用するとエラーが発生します。

_org.glassfish.hk2.api.UnsatisfiedDependencyException: There was no object available for injection at SystemInjecteeImpl(requiredType=PricingService,parent=PricingResource,qualifiers={},position=0,optional=false,self=false,unqualified=null,1633188703)
_

私はこの概念にまったく慣れておらず、推奨されない例がいくつかあるため、非常に複雑に見えます。私が理解しているように、DIを機能させる方法はいくつかあります:ネイティブHK2、Spring/HK2 Bridge。設定がより簡単で簡単なものは何ですか? Jersey 2.x用にプログラムで設定する方法(XMLのファンではない)

ResourceConfig

_import org.glassfish.jersey.server.ResourceConfig;

public class ApplicationConfig  extends ResourceConfig {
    public ApplicationConfig() {
        register(new ApplicationBinder());
        packages(true, "api");
    }
}
_

AbstractBinder

_public class ApplicationBinder extends AbstractBinder {
    @Override
    protected void configure() {
        bind(PricingService.class).to(PricingService.class).in(Singleton.class);
    }
}
_

PricingResource

_@Path("/prices")
public class PricingResource {
    private final PricingService pricingService;

    @Inject
    public PricingResource(PricingService pricingService) {
        this.pricingService = pricingService;
    }

    @GET
    @Produces(MediaType.APPLICATION_JSON)
    public Collection<Price> findPrices() {
        return pricingService.findPrices();
    }
}
_

PricingService

_@Singleton
public class PricingService {
   // no constructors...
// findPrices() ...

}
_

[〜#〜] update [〜#〜]

_public class Main {
    public static final String BASE_URI = "http://localhost:8080/api/";

    public static HttpServer startServer() {
        return createHttpServerWith(new ResourceConfig().packages("api").register(JacksonFeature.class));
    }

    private static HttpServer createHttpServerWith(ResourceConfig rc) {
        HttpServer httpServer = GrizzlyHttpServerFactory.createHttpServer(URI.create(BASE_URI), rc);
        StaticHttpHandler staticHttpHandler = new StaticHttpHandler("src/main/webapp");
        staticHttpHandler.setFileCacheEnabled(false);
        staticHttpHandler.start();
        httpServer.getServerConfiguration().addHttpHandler(staticHttpHandler);
        return httpServer;
    }

    public static void main(String[] args) throws IOException {
        System.setProperty("Java.util.logging.config.file", "src/main/resources/logging.properties");
        final HttpServer server = startServer();

        System.out.println(String.format("Jersey app started with WADL available at "
                + "%sapplication.wadl\nHit enter to stop it...", BASE_URI));
        server.start();
        System.in.read();
        server.stop();
    }

}
_

PDATE3:

_public class PricingResourceTest extends JerseyTest {
    @Mock
    private PricingService pricingServiceMock;

    @Override
    protected Application configure() {
        MockitoAnnotations.initMocks(this);
        enable(TestProperties.LOG_TRAFFIC);
        enable(TestProperties.DUMP_ENTITY);

        ResourceConfig config = new ResourceConfig(PricingResource.class);
        config.register(new AbstractBinder() {
            @Override
            protected void configure() {
                bind(pricingServiceMock).to(PricingService.class);
            }
        });
        return config;
    }

    @Test
    public void testFindPrices(){
        when(pricingServiceMock.findPrices()).thenReturn(getMockedPrices());
        Response response  = target("/prices")
                .request()
                .get();
        verify(pricingServiceMock).findPrices();
        List<Price> prices = response.readEntity(new GenericType<List<Price>>(){});
//        assertEquals("Should return status 200", 200, response.getStatus());
        assertTrue(prices.get(0).getId() == getMockedPrices().get(0).getId());
    }

    private List<Price> getMockedPrices(){
        List<Price> mockedPrices = Arrays.asList(new Price(1L, 12.0, 50.12, 12L));
        return mockedPrices;
    }
}
_

JUnit出力:

_INFO: 1 * Client response received on thread main
1 < 200
1 < Content-Length: 4
1 < Content-Type: application/json
[{}]


Java.lang.AssertionError
_

デバッグ中:

prices.get(0)は、すべてのフィールドにPriceが割り当てられたnullオブジェクトです。


PDATE4:

configure()に追加:

_ config.register(JacksonFeature.class);
 config.register(JacksonJsonProvider.class);
_

Junitの出力が少し改善されました。

_INFO: 1 * Client response received on thread main
1 < 200
1 < Content-Length: 149
1 < Content-Type: application/json
[{"id":2,"recurringPrice":122.0,"oneTimePrice":6550.12,"recurringCount":2},{"id":2,"recurringPrice":122.0,"oneTimePrice":6550.12,"recurringCount":2}]
_

実際、リストpricesには正しい数のpricesがありますが、すべての価格のフィールドはnullです。これは、問題がエンティティを読み取る可能性があるという仮定につながります。

_List<Price> prices = response.readEntity(new GenericType<List<Price>>(){});
_

修正方法はこちら

Moxy依存関係を次のように変更します。

_<dependency>
    <groupId>org.glassfish.jersey.media</groupId>
    <artifactId>jersey-media-json-jackson</artifactId>
</dependency>
_

「価格」オブジェクトに注釈を追加します。

_@XmlRootElement
@JsonIgnoreProperties(ignoreUnknown = true)
_
11
J.Olufsen

InjectableProviderを忘れてください。必要ありません。問題は、mockサービスが注入されるサービスではないことです。これは、DIフレームワークによって作成されたものです。そのため、モックサービスの変更を確認しますが、これは変更されたことはありません。

そのため、モックをDIフレームワークにバインドする必要があります。テスト用に別のAbstractBinderを作成するだけです。モックをバインドする単純な匿名のものでもかまいません

_ResourceConfig config = new ResourceConfig(PricingResource.class);
config.register(new AbstractBinder() {
    @Override
    protected void configure() {
        bind(pricingServiceMock).to(PricingService.class);
    }
});
_

ここでは、模擬サービスを単にバインドしています。そのため、フレームワークはリソースにモックを注入します。リクエストで変更すると、アサーションに変更が表示されます

ああ、まだwhen(..).then(..)を実行して、モックサービスのデータを初期化する必要があります。それはあなたが欠けているものでもあります

_@Test
public void testFindPrices(){
    Mockito.when(pricingServiceMock.findSomething()).thenReturn(list);
_
5
Paul Samsotha

次の依存関係をアプリケーションに追加して、この問題を修正しました。コンパイルグループ: 'org.glassfish.jersey.containers.glassfish'、名前: 'jersey-gf-cdi'、バージョン: '2.14'

次に、「AbstractBinder」関連のコードを用意する必要はありません。

1
nrkkalyan

Beans.xmlがないか、間違った場所に配置されている場合も、同じエラーが発生します。これは私を助けました: beans.xmlはどこに置くべきですか?

0
luca.vercelli