I am having a bizarre problem with my JerseyTest class.
When executing my test code and putting a break point on line 203 of org.glassfish.jersey.message.internal.ReaderInterceptorExecutor, I see that my reader is not in reader.workers. However, as you can see below, I register this MessageBodyReader in the ResourceConfig.
All relevant code is provided below.
My custom MessageBodyReader/Writer
@Provider
@Produces({V1_JSON})
@Consumes({V1_JSON})
public class JsonMessageBodyHandlerV1
implements
MessageBodyWriter<Object>,
MessageBodyReader<Object> {
...
}
And yes, isReadable
returns true.
When debugging, I see that the code hits writeTo
but not readFrom
.
Test code that fails
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;
}
}
(Pulling from this example.)
The resource it's testing...
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;
}
}
(Note that the web service annotations such as @GET are in the interface.)
Generates this fail trace
org.glassfish.jersey.message.internal.MessageBodyProviderNotFoundException: MessageBodyReader not found for media type=application/vnd.com.company-v1+json, type=class com.company.rest.v1.resources.location.json.LocationListV1, genericType=class com.company.rest.v1.resources.location.json.LocationListV1. at org.glassfish.jersey.message.internal.ReaderInterceptorExecutor$TerminalReaderInterceptor.aroundReadFrom(ReaderInterceptorExecutor.java:207) at org.glassfish.jersey.message.internal.ReaderInterceptorExecutor.proceed(ReaderInterceptorExecutor.java:139) at org.glassfish.jersey.message.internal.MessageBodyFactory.readFrom(MessageBodyFactory.java:1109) at org.glassfish.jersey.message.internal.InboundMessageContext.readEntity(InboundMessageContext.java:851) at org.glassfish.jersey.message.internal.InboundMessageContext.readEntity(InboundMessageContext.java:785) at org.glassfish.jersey.client.InboundJaxrsResponse.readEntity(InboundJaxrsResponse.java:96) at org.glassfish.jersey.client.JerseyInvocation.translate(JerseyInvocation.java:761) at org.glassfish.jersey.client.JerseyInvocation.access$500(JerseyInvocation.java:90) at org.glassfish.jersey.client.JerseyInvocation$2.call(JerseyInvocation.java:671) at org.glassfish.jersey.internal.Errors.process(Errors.java:315) at org.glassfish.jersey.internal.Errors.process(Errors.java:297) at org.glassfish.jersey.internal.Errors.process(Errors.java:228) at org.glassfish.jersey.process.internal.RequestScope.runInScope(RequestScope.java:422) at org.glassfish.jersey.client.JerseyInvocation.invoke(JerseyInvocation.java:667) at org.glassfish.jersey.client.JerseyInvocation$Builder.method(JerseyInvocation.java:396) at org.glassfish.jersey.client.JerseyInvocation$Builder.get(JerseyInvocation.java:296) at com.company.rest.resources.location.TestLocationResource.basicTest(TestLocationResource.java:47) [...]
... with this console output
[...]
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)
[...]
[...]
Followed by this, implying that there was a successful response
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]
Anybody have any idea what I am doing wrong?
client().register(JsonMessageBodyHandlerV1.class);
outside ofconfigure()
(such as within a@Test
or in a custom@Before
), it works. Still don't know how to get rid of those spammy 'Could not find a suitable constructor' error messages though. – Ryan