I have an annotated Spring-Jersey application. I am trying to set up unit test for my controllers using JerseyTest
. I am getting the following errors on running the test that I am not able to figure out. What have I missed?
SEVERE: Following issues have been detected:
WARNING: No injection source found for a parameter of type public com.example.services.dto.UnitDto com.example.apis.UnitResource.getUnits(com.example.services.dto.PointDto) throws com.example.exceptions.PointOutsideBounds at index 2.
Validation of the application resource model has failed during application initialization.
[[FATAL] No injection source found for a parameter of type public com.example.services.dto.UnitDto com.example.apis.UnitResource.getUnits(com.example.services.dto.PointDto) throws com.example.exceptions.PointOutsideBounds at index 2.; source='ResourceMethod{httpMethod=GET, consumedTypes=[], producedTypes=[application/json], suspended=false, suspendTimeout=0, suspendTimeoutUnit=MILLISECONDS, invocable=Invocable{handler=ClassBasedMethodHandler{handlerClass=class com.example.apis.UnitResource, handlerConstructors=[org.glassfish.jersey.server.model.HandlerConstructor@31a5870e]}, definitionMethod=public com.example.services.dto.UnitDto com.example.apis.UnitResource.getUnits(com.example.services.dto.PointDto) throws com.example.exceptions.PointOutsideBounds, parameters=[Parameter [type=class com.example.services.dto.PointDto, source=contains, defaultValue=null]], responseType=class com.example.services.dto.UnitDto}, nameBindings=[]}']
at org.glassfish.jersey.server.ApplicationHandler.initialize(ApplicationHandler.java:555)
The controller class is as follows:
@Component
@Path("/app/units")
public class UnitResource {
@Context
private UriInfo uriInfo;
@Context
private Request request;
@Inject
private UnitService unitService;
@Inject
public UnitResource(@Named("UnitService") UnitService unitService) {
this.unitService = unitService;
}
@GET
@Produces(MediaType.APPLICATION_JSON)
@Timed(absolute = true, name = "getUnitForPoint")
public UnitDto getUnits(@QueryParam("contains") @NotNull PointDto point) throws PointOutsideBounds {
return unitService.getUnitForPoint(point);
}
}
The test class is as follows:
public class UnitResourceTest extends JerseyTest {
@Mock
private UnitService unitService;
@Override
protected ResourceConfig configure() {
ResourceConfig rc = new ResourceConfig()
// .register(new UnitResource(Mockito.mock(UnitService.class))) -- has the same effect
.register(UnitResource.class)
.property("contextConfig", new AnnotationConfigApplicationContext(ApplicationConfiguration.class));
enable(TestProperties.LOG_TRAFFIC);
enable(TestProperties.DUMP_ENTITY);
forceSet(TestProperties.CONTAINER_PORT, "0");
return rc;
}
@Before
public void setUp() throws Exception {
super.setUp();
initMocks(this);
}
@Override
protected TestContainerFactory getTestContainerFactory() {
return new InMemoryTestContainerFactory();
}
@Test
public void testGetUnit() throws PointOutsideBounds {
Response response = target()
.path("/app/units")
.queryParam("contains", new Point(0.0,0.0).toJson())
.request(MediaType.APPLICATION_JSON_TYPE)
.get();
assertThat(response.getStatus(), is(Response.Status.OK));
}
}
The application configuration class is:
@Configuration
@ComponentScan("com.example")
public class ApplicationConfiguration {
@Bean(name="UnitService")
public UnitService unitService() {
return new UnitService();
}
}
My Gradle dependencies for test configuration are:
dependencies {
// Using junit-dep package to get junit without hamcrest dependency
testCompile("junit:junit-dep:4.8.2")
testCompile("org.hamcrest:hamcrest-all:1.3")
testCompile("org.mockito:mockito-all:1.8.4")
testCompile ('org.glassfish.jersey.test-framework:jersey-test-framework-core:2.22.2')
testCompile('org.glassfish.jersey.test-framework.providers:jersey-test-framework-provider-inmemory:2.22.2')
}
configurations {
testCompile.exclude group: 'org.glassfish.jersey.ext', module: 'jersey-spring3'
}
Note: For the most part, this answer applies to all
@XxxParam
annotated parameters.The
PointDto
parameter seems to be the problemQuery parameters are Strings. Jersey has the capability to convert that String to some basic types like
int
,boolean
,Date
, etc. But it has no idea how to create thePointDto
from that String. That doesn't mean that we can't use custom types. We just need to follow some rules:Have a constructor that accepts a String. Then we need to construct the object ourselves from that String. For example
It's a bit of work.
Another option is to have a static
fromString(String)
or staticvalueOf(String)
in the class. Jersey will invoke this method to construct the object. So for instance you can have in yourPointDto
classYou can have a
ParamConverterProvider
. I won't put an example, but you can read more in this good article about how you can implement it. You can also see this postNote, the information presented in this answer is in the javadoc for
@QueryParam
.