J.O*_*sen 12 java dependency-injection glassfish jersey 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,unqualified=null,1633188703)
Run Code Online (Sandbox Code Playgroud)
我对这个概念很陌生,看起来很复杂,因为有些例子似乎已被弃用了.据我所知,有几种方法可以使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");
}
}
Run Code Online (Sandbox Code Playgroud)
AbstractBinder
public class ApplicationBinder extends AbstractBinder {
@Override
protected void configure() {
bind(PricingService.class).to(PricingService.class).in(Singleton.class);
}
}
Run Code Online (Sandbox Code Playgroud)
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();
}
}
Run Code Online (Sandbox Code Playgroud)
PricingService
@Singleton
public class PricingService {
// no constructors...
// findPrices() ...
}
Run Code Online (Sandbox Code Playgroud)
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();
}
}
Run Code Online (Sandbox Code Playgroud)
UPDATE3:
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;
}
}
Run Code Online (Sandbox Code Playgroud)
JUnit输出:
INFO: 1 * Client response received on thread main
1 < 200
1 < Content-Length: 4
1 < Content-Type: application/json
[{}]
java.lang.AssertionError
Run Code Online (Sandbox Code Playgroud)
调试时:
prices.get(0)是Price已null分配给所有字段的对象.
UPDATE4:
添加到configure():
config.register(JacksonFeature.class);
config.register(JacksonJsonProvider.class);
Run Code Online (Sandbox Code Playgroud)
现在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}]
Run Code Online (Sandbox Code Playgroud)
确实列表的prices数量是正确的,prices但所有价格的字段都是空的.这导致假设问题可能是阅读实体:
List<Price> prices = response.readEntity(new GenericType<List<Price>>(){});
Run Code Online (Sandbox Code Playgroud)
将Moxy依赖项更改为:
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-json-jackson</artifactId>
</dependency>
Run Code Online (Sandbox Code Playgroud)
并在"价格"对象上添加注释.
@XmlRootElement
@JsonIgnoreProperties(ignoreUnknown = true)
Run Code Online (Sandbox Code Playgroud)
忘了InjectableProvider.你不需要它.问题是模拟服务不是被注入的服务.它是由DI框架创建的.因此,您正在检查模拟服务的更改,这些更改从未被触及过.
所以你需要做的是将模拟与DI框架绑定.您可以简单地创建另一个AbstractBinder用于测试.它可以是一个简单的匿名,你将绑定模拟
ResourceConfig config = new ResourceConfig(PricingResource.class);
config.register(new AbstractBinder() {
@Override
protected void configure() {
bind(pricingServiceMock).to(PricingService.class);
}
});
Run Code Online (Sandbox Code Playgroud)
在这里,您只需绑定模拟服务.所以框架会将模拟注入资源.现在,当您在请求中修改它时,将在断言中看到更改
哦,你仍然需要when(..).then(..)在模拟服务中初始化数据.这也是你所缺少的
@Test
public void testFindPrices(){
Mockito.when(pricingServiceMock.findSomething()).thenReturn(list);
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
21519 次 |
| 最近记录: |