【问题标题】:Custom MessageBodyReader not found in JerseyTest在 JerseyTest 中找不到自定义 MessageBodyReader
【发布时间】:2013-10-29 22:55:44
【问题描述】:

我的 JerseyTest 课程有一个奇怪的问题。

在执行我的测试代码并在org.glassfish.jersey.message.internal.ReaderInterceptorExecutor 的第 203 行设置断点时,我看到我的阅读器不在 reader.workers 中。但是,如下所示,我在 ResourceConfig 中注册了这个 MessageBodyReader。

下面提供了所有相关代码。

我的自定义 MessageBodyReader/Writer

@Provider
@Produces({V1_JSON})
@Consumes({V1_JSON})
public class JsonMessageBodyHandlerV1
    implements
      MessageBodyWriter<Object>,
      MessageBodyReader<Object> {
  ...
}

是的,isReadable 返回 true

调试时,我看到代码点击了writeTo,但没有readFrom

失败的测试代码

public class TestLocationResource extends JerseyTest {

  public static class LocationResourceHK2Binder extends AbstractBinder {

    @Override
    protected void configure() {
      // Singleton bindings.
      bindAsContract(LocationDao.class).in(Singleton.class);

      // Singleton instance bindings.
      bind(new FakeLocationDao()).to(LocationDao.class);
    }
  }

  @Test
  public void basicTest() {

    LocationListV1 actualResponse = /**/
    /**/target(LocationResourceV1.PathFields.PATH_ROOT)
    /*   */.path(LocationResourceV1.PathFields.SUBPATH_LIST)
    /*   */.request(V1_JSON)
    /*   */.header(HEADER_API_KEY, "abcdefg")
    /*   */.get(LocationListV1.class);

    assertEquals(10, actualResponse.getLocations().size());
  }

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

    ResourceConfig rc = new ResourceConfig();
    rc.registerClasses(LocationResourceV1.class, JsonMessageBodyHandlerV1.class);
    rc.register(new LocationResourceHK2Binder());

    return rc;
  }
}

(来自this example。)

它正在测试的资源...

public class LocationResourceV1 implements ILocationResourceV1 {
  ...

  @Inject
  private LocationDao daoLoc;

  private final LocationTranslator translator = new LocationTranslator();

  @Override
  public LocationListV1 listV1(String apiKey) {
    return translator.translate(daoLoc.query(LocationFilters.SELECT_ALL));
  }

  ...

  @VisibleForTesting
  public void setLocationDao(LocationDao dao) {
    this.daoLoc = dao;
  }
}

(注意@GET等web服务注解在接口中。)

生成此失败跟踪

org.glassfish.jersey.message.internal.MessageBodyProviderNotFoundException: 找不到媒体的 MessageBodyReader 类型=应用程序/vnd.com.company-v1+json,类型=类 com.company.rest.v1.resources.location.json.LocationListV1, genericType=类 com.company.rest.v1.resources.location.json.LocationListV1。 在 org.glassfish.jersey.message.internal.ReaderInterceptorExecutor$TerminalReaderInterceptor.aroundReadFrom(ReaderInterceptorExecutor.java:207) 在 org.glassfish.jersey.message.internal.ReaderInterceptorExecutor.proceed(ReaderInterceptorExecutor.java:139) 在 org.glassfish.jersey.message.internal.MessageBodyFactory.readFrom(MessageBodyFactory.java:1109) 在 org.glassfish.jersey.message.internal.InboundMessageContext.readEntity(InboundMessageContext.java:851) 在 org.glassfish.jersey.message.internal.InboundMessageContext.readEntity(InboundMessageContext.java:785) 在 org.glassfish.jersey.client.InboundJaxrsResponse.readEntity(InboundJaxrsResponse.java:96) 在 org.glassfish.jersey.client.JerseyInvocation.translate(JerseyInvocation.java:761) 在 org.glassfish.jersey.client.JerseyInvocation.access$500(JerseyInvocation.java:90) 在 org.glassfish.jersey.client.JerseyInvocation$2.call(JerseyInvocation.java:671) 在 org.glassfish.jersey.internal.Errors.process(Errors.java:315) 在 org.glassfish.jersey.internal.Errors.process(Errors.java:297) 在 org.glassfish.jersey.internal.Errors.process(Errors.java:228) 在 org.glassfish.jersey.process.internal.RequestScope.runInScope(RequestScope.java:422) 在 org.glassfish.jersey.client.JerseyInvocation.invoke(JerseyInvocation.java:667) 在 org.glassfish.jersey.client.JerseyInvocation$Builder.method(JerseyInvocation.java:396) 在 org.glassfish.jersey.client.JerseyInvocation$Builder.get(JerseyInvocation.java:296) 在 com.company.rest.resources.location.TestLocationResource.basicTest(TestLocationResource.java:47) [...]

... 使用此控制台输出

[...]
INFO: [HttpServer] Started.
Oct 29, 2013 4:26:16 PM org.glassfish.jersey.filter.LoggingFilter log
INFO: 1 * LoggingFilter - Request received on thread main
1 > GET http://localhost:9998/location/list
1 > Accept: application/vnd.com.company-v1+json
1 > X-ApiKey: abcdefg

Oct 29, 2013 3:30:21 PM org.glassfish.jersey.internal.Errors logErrors
WARNING: The following warnings have been detected: WARNING: HK2 service reification failed for [com.company.persistence.dao.intf.LocationDao] with an exception:
MultiException stack 1 of 2
java.lang.NoSuchMethodException: Could not find a suitable constructor in com.company.persistence.dao.intf.LocationDao class.
    at org.glassfish.jersey.internal.inject.JerseyClassAnalyzer.getConstructor(JerseyClassAnalyzer.java:189)
    at org.jvnet.hk2.internal.Utilities.getConstructor(Utilities.java:159)
    at org.jvnet.hk2.internal.ClazzCreator.initialize(ClazzCreator.java:125)
    at org.jvnet.hk2.internal.ClazzCreator.initialize(ClazzCreator.java:176)
    at org.jvnet.hk2.internal.SystemDescriptor.internalReify(SystemDescriptor.java:649)
    at org.jvnet.hk2.internal.SystemDescriptor.reify(SystemDescriptor.java:604)
    at org.jvnet.hk2.internal.ServiceLocatorImpl.reifyDescriptor(ServiceLocatorImpl.java:396)
    [...]
MultiException stack 2 of 2
java.lang.IllegalArgumentException: Errors were discovered while reifying SystemDescriptor(
    implementation=com.company.persistence.dao.intf.LocationDao
    contracts={com.company.persistence.dao.intf.LocationDao}
    scope=org.glassfish.jersey.process.internal.RequestScoped
    qualifiers={}
    descriptorType=CLASS
    descriptorVisibility=NORMAL
    metadata=
    rank=0
    loader=org.glassfish.hk2.utilities.binding.AbstractBinder$2@568bf3ec
    proxiable=null
    proxyForSameScope=null
    analysisName=null
    id=143
    locatorId=0
    identityHashCode=2117810007
    reified=false)
    at org.jvnet.hk2.internal.SystemDescriptor.reify(SystemDescriptor.java:615)
    at org.jvnet.hk2.internal.ServiceLocatorImpl.reifyDescriptor(ServiceLocatorImpl.java:396)
    at org.jvnet.hk2.internal.ServiceLocatorImpl.narrow(ServiceLocatorImpl.java:1916)
    at org.jvnet.hk2.internal.ServiceLocatorImpl.access$700(ServiceLocatorImpl.java:113)
    at org.jvnet.hk2.internal.ServiceLocatorImpl$6.compute(ServiceLocatorImpl.java:993)
    at org.jvnet.hk2.internal.ServiceLocatorImpl$6.compute(ServiceLocatorImpl.java:988)
    [...]
    [...]
    (Above is repeated 4 times)
    [...]
    [...]

后面跟着this,表示有响应成功

Oct 29, 2013 3:30:22 PM org.glassfish.jersey.filter.LoggingFilter log
INFO: 2 * LoggingFilter - Response received on thread main
2 < 200
2 < Date: Tue, 29 Oct 2013 22:30:21 GMT
2 < Content-Length: 16
2 < Content-Type: application/vnd.com.company-v1+json
{"locations":[]}

Oct 29, 2013 3:30:22 PM org.glassfish.jersey.test.grizzly.GrizzlyTestContainerFactory$GrizzlyTestContainer stop
INFO: Stopping GrizzlyTestContainer...
Oct 29, 2013 3:30:22 PM org.glassfish.grizzly.http.server.NetworkListener stop
INFO: Stopped listener bound to [localhost:9998]

有人知道我做错了什么吗?

【问题讨论】:

  • 我可能是错的,但这看起来像泽西虫。当我在configure() 之外执行client().register(JsonMessageBodyHandlerV1.class); 时(例如在@Test 或自定义@Before 中),它可以工作。仍然不知道如何摆脱那些垃圾邮件“找不到合适的构造函数”错误消息。

标签: rest glassfish jersey jax-rs jersey-2.0


【解决方案1】:

第一个堆栈跟踪来自您的客户端,因为您没有在那里注册消息体提供程序(因此无法找到它)。 JerseyTest#configure 方法应该只用于配置服务器端。还有另一种方法称为JerseyTest#configureClient,旨在用于客户端。如果要使用自定义提供程序,则需要覆盖这两种方法。

第二个堆栈跟踪来自您的LocationResourceHK2Binder。由

bindAsContract(LocationDao.class).in(Singleton.class);

你告诉 HK2 LocationDao 类应该被实例化为一个单例,然后 HK2 会将它注入到 LocationDao 类型中。您可能需要更改您的活页夹以使用类似的东西:

bind(new FakeLocationDao()).to(LocationDao.class);

有关此主题的更多信息,请参阅Custom Injection and Lifecycle Management

【讨论】:

  • 谢谢 Michal,我不知道 configureClient。至于您的活页夹评论,这 -- bind(new FakeLocationDao()).to(LocationDao.class).in(Singleton.class) 无法通过他们的 API 实现,因为第一个 bind(T service) 返回一个 ScopedBindingBuilder 不允许您指定合同(in。)我的方式它设置了“工作”,但它只是在控制台警告消息中发送垃圾邮件异常。我查看了您提供的链接,但不知道如何解决此问题。
  • 也就是说bind(mockedDaoInstance).to(LocationDao.class).to(new TypeLiteral&lt;Singleton&gt;() {});和上面的效果一样。
  • 哦$h,我错了。我正在运行整个测试套件,但仍然看到异常——愚蠢的我。我上面评论中的那行有效。谢谢你,先生:)
  • 正确,删除了.in(...) 调用。当您绑定一个实例时,它根据定义在单例范围内。过失。
猜你喜欢
  • 2013-05-03
  • 1970-01-01
  • 2014-08-03
  • 2015-01-28
  • 2020-08-07
  • 2014-09-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多