Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/384.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java UnsatifiedPendencyException:SystemInjecteImpl上没有可供注入的对象_Java_Dependency Injection_Jersey_Glassfish_Hk2 - Fatal编程技术网

Java UnsatifiedPendencyException:SystemInjecteImpl上没有可供注入的对象

Java UnsatifiedPendencyException:SystemInjecteImpl上没有可供注入的对象,java,dependency-injection,jersey,glassfish,hk2,Java,Dependency Injection,Jersey,Glassfish,Hk2,在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,

在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桥。什么配置更简单、更直接?如何以编程方式为Jersey 2.x设置(不喜欢XML)

资源配置

import org.glassfish.jersey.server.ResourceConfig;

public class ApplicationConfig  extends ResourceConfig {
    public ApplicationConfig() {
        register(new ApplicationBinder());
        packages(true, "api");
    }
}
@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();
    }
}
@Singleton
public class PricingService {
   // no constructors...
// findPrices() ...

}
AbstractBinder

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

import org.glassfish.jersey.server.ResourceConfig;

public class ApplicationConfig  extends ResourceConfig {
    public ApplicationConfig() {
        register(new ApplicationBinder());
        packages(true, "api");
    }
}
@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();
    }
}
@Singleton
public class PricingService {
   // no constructors...
// findPrices() ...

}

更新

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();
    }

}
更新3:

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;
    }
}
INFO: 1 * Client response received on thread main
1 < 200
1 < Content-Length: 4
1 < Content-Type: application/json
[{}]


java.lang.AssertionError
现在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}]
下面是如何修复它 将Moxy依赖项更改为:

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

忘记
InjectableProvider
。你不需要它。问题是模拟服务不是被注入的服务。它是由DI框架创建的。因此,您正在检查mock服务上的更改,该服务从未被触及过

因此,您需要做的是将mock与DI框架绑定。您只需为测试创建另一个
AbstractBinder
。它可以是一个简单的匿名文件,您将在其中绑定模拟文件

ResourceConfig config = new ResourceConfig(PricingResource.class);
config.register(new AbstractBinder() {
    @Override
    protected void configure() {
        bind(pricingServiceMock).to(PricingService.class);
    }
});
在这里,您只需绑定模拟服务。因此,框架将把mock注入到资源中。现在,当您在请求中修改它时,将在断言中看到更改

哦,您仍然需要在(..)时执行
,然后(..)
初始化模拟服务中的数据。这也是你所缺少的

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

我通过向应用程序添加以下依赖项修复了此问题。 编译组:“org.glassfish.jersey.containers.glassfish”,名称:“jersey gf cdi”,版本:“2.14”


这样就不需要任何与“AbstractBinder”相关的代码。

如果beans.xml丢失或放置在错误的位置,也会出现相同的错误。这对我很有帮助:

看看这个,如果我把所有的东西都放在一件运动衫上测试,我可以告诉你,用你提供的东西,它应该可以很好地工作。试着自己做,然后试着缩小问题的范围。我不知道还能告诉你什么。我认为它不起作用的唯一方法(在真正的服务器环境中)是使用web.xml,而ResourceConfig类甚至没有被使用。如果是这种情况,请查看您在帖子中甚至没有使用
ResourceConfig
。您正在创建一个完全不同的
createHttpServerWith(new ResourceConfig()。
ResourceConfig在
Main
ApplicationConfig
中定义,但看起来这两个配置不在一起…..可能是为什么要链接它们?只需使用
createHttpServerWith(new ApplicationConfig())
您缺少数据的模拟初始化的主要原因。您应该在测试方法中进行此操作。就像您在上一个问题中所做的一样,该问题现在已在本问题中丢失。我更新了测试,但仍然失败:
assertTrue(prices.get(0.getId()==getMockedPrices().get(0.getId());
您是否在(..)时使用
初始化模拟数据
?我想是的,我的整个测试都发布在
UPDATE3
中。你做过任何调试吗?比如检查资源方法中的列表。数据在列表中吗?如果是,那么似乎是序列化问题。你没有明白我说的。资源方法是服务器端带有
@GET
的方法。检查从资源方法内部调用服务返回的列表。如果需要,可以添加一个简单的S.O.P。如果从服务中检索价格后价格在列表中,则表示服务器在序列化所有注入资源(bean)的第一个响应时遇到问题必须是CDI感知的。它必须可以被CDI检测到。我们可以使用bean discovery mode=“all”-然后CDI扫描所有类或bean discovery mode=“annotated”,并用正确的注释标记我们的类:from.Iprefer@Dependent或@RequestScoped