Java UnsatisfiedDependencyException: SystemInjecteeImpl 中没有可注入的对象
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/36889504/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
UnsatisfiedDependencyException: There was no object available for injection at SystemInjecteeImpl
提问by J.Olufsen
There are errors when using DI in Jersey Rest application:
在 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)
I am quite new to the concept and it appears quite complicated since there are some examples seems to be deprecated. As I understand there are a few ways to make DI work: native HK2, Spring/HK2 Bridge. What is easier and more straightforward to configure? How to set up programmatically (not a fan of XML) for Jersey 2.x?
我对这个概念很陌生,它看起来很复杂,因为有些示例似乎已被弃用。据我了解,有几种方法可以使 DI 工作:本地 HK2、Spring/HK2 Bridge。什么配置更简单、更直接?如何以编程方式(不喜欢 XML)为 Jersey 2.x 设置?
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(HymansonFeature.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();
}
}
UPDATE3:
更新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;
}
}
JUnit output:
JUnit 输出:
INFO: 1 * Client response received on thread main
1 < 200
1 < Content-Length: 4
1 < Content-Type: application/json
[{}]
java.lang.AssertionError
While debugging:
调试时:
prices.get(0)
is Price
object that has null
assigned to all fields.
prices.get(0)
是分配给所有字段的Price
对象null
。
UPDATE4:
更新4:
Added to configure()
:
添加到configure()
:
config.register(HymansonFeature.class);
config.register(HymansonJsonProvider.class);
Now Junit output a bit better:
现在 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}]
Indeed list prices
has correct number of prices
but all prices' fields is null. That leads to assumption that problem might be reading entity:
确实列表prices
具有正确的数量,prices
但所有价格的字段都为null。这导致假设问题可能是读取实体:
List<Price> prices = response.readEntity(new GenericType<List<Price>>(){});
Here is how to fix it
这是修复方法
Change Moxy dependency to:
将 Moxy 依赖更改为:
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-json-Hymanson</artifactId>
</dependency>
and add annotations on 'Price' object.
并在“价格”对象上添加注释。
@XmlRootElement
@JsonIgnoreProperties(ignoreUnknown = true)
采纳答案by Paul Samsotha
Forget the InjectableProvider
. You don't need it. The problem is that the mockservice is not the one being injected. It is the one created by the DI framework. So you are checking for changes on the mock service, which has never been touched.
忘记了InjectableProvider
。你不需要它。问题是模拟服务不是被注入的服务。它是由 DI 框架创建的。因此,您正在检查从未接触过的模拟服务上的更改。
So what you need to do is bind the mock with the DI framework. You can simply create another AbstractBinder
for testing. It can be a simple anonymous one, where you will bind the mock
所以你需要做的是将模拟与 DI 框架绑定。您可以简单地创建另一个AbstractBinder
用于测试。它可以是一个简单的匿名的,您将在其中绑定模拟
ResourceConfig config = new ResourceConfig(PricingResource.class);
config.register(new AbstractBinder() {
@Override
protected void configure() {
bind(pricingServiceMock).to(PricingService.class);
}
});
Here you are simply binding the mocked service. So the framework will inject the mock into the resource. Now when you modify it in the request, the changes will be seen in the assertion
在这里,您只是绑定了模拟服务。所以框架会将模拟注入资源。现在,当您在请求中修改它时,将在断言中看到更改
Oh and you still need to do your when(..).then(..)
to initialize the data in the mock service. That is also what you are missing
哦,您仍然需要when(..).then(..)
在模拟服务中初始化数据。这也是你所缺少的
@Test
public void testFindPrices(){
Mockito.when(pricingServiceMock.findSomething()).thenReturn(list);
回答by nrkkalyan
I fixed this problem by adding the following dependency to my application. compile group: 'org.glassfish.jersey.containers.glassfish', name: 'jersey-gf-cdi', version: '2.14'
我通过向我的应用程序添加以下依赖项来解决这个问题。编译组:'org.glassfish.jersey.containers.glassfish',名称:'jersey-gf-cdi',版本:'2.14'
Then there is no need to have any "AbstractBinder" related code.
那么就不需要有任何“AbstractBinder”相关的代码。
回答by luca.vercelli
The same error arise if beans.xml is missing or placed in the wrong place. This helped me: Where should beans.xml be placed?
如果 beans.xml 丢失或放置在错误的位置,则会出现相同的错误。这对我有帮助:beans.xml 应该放在哪里?