Question

We have a problem with our tests that the field UriInfo is not correctly injected when the resource is wrapped in a TransactionalProxy. We tried using the SpringResourceFactory but that did not help either.

I tried to extract the relevant classes for this usecase:


public class InMemoryClientFactory implements FactoryBean<InMemoryClientExecutor>{

    @Inject
    private SessionResource sessionResource;

    @Override
    public InMemoryClientExecutor getObject() throws Exception {
        Dispatcher dispatcher = MockDispatcherFactory.createDispatcher();
        Registry registry = dispatcher.getRegistry();
        registry.addSingletonResource(sessionResource);
        final InMemoryClientExecutor inMemoryClientExecutor = new InMemoryClientExecutor(dispatcher);
    }

    @Override
    public Class getObjectType() {
        return InMemoryClientExecutor.class;
    }

    @Override
    public boolean isSingleton() {
        return true;
    }
}

@Path("session")
public interface SessionResource {

    @GET
    @Path("{sessionId}")
    @Produces({MediaType.APPLICATION_XML})
    Response get(@PathParam("sessionId") String sessionId);

    @DELETE
    @Path("{sessionId}")
    Response delete(@PathParam("sessionId") String sessionId);
}

@Service
@Transactional
public class SessionResourceImpl implements SessionResource {

    @Context
    private UriInfo uriInfo;

    @Override
    public Response get(String sessionId) {
         // uriInfo will be null here
         String url = uriInfo.getBaseUriBuilder().path(SessionResource.class).path(SessionResource.class, "delete").build(sessionId)
                .toString());

        return Response.ok(session).build();

    @Override
    public Response delete(String sessionId) {
         System.out.println("Deleted Session "+1);
    }
}


@ContextConfiguration(locations = ["classpath:/META-INF/testContext.xml"])
@Transactional
@RunWith(SpringJUnit4ClassRunner.class)
public class SessionResourceIT {

    @Inject
    InMemoryRestClientFactory inMemoryClientFactory;

    @Inject
    SessionResource resource;

    @Test
    public void test() {
        SessionResource resource = inMemoryClientFactory.createProxy(SessionResource.class);

        ClientResponse cr = client.get(sessionId);
        assertNotNull(cr.getEntity(String.class));
    }
}
Was it helpful?

Solution

A possible workaround is to unwrap the transactional proxy for the tests, this works as long as the test itself is annotated with @Transactional. I hope someone has a better solution than this.


public class InMemoryClientFactory implements FactoryBean<InMemoryClientExecutor>{

    @Inject
    private SessionResource sessionResource;

    @Override
    public InMemoryClientExecutor getObject() throws Exception {
        Dispatcher dispatcher = MockDispatcherFactory.createDispatcher();
        Registry registry = dispatcher.getRegistry();
        registry.addSingletonResource(unwrapProxy(sessionResource));
        final InMemoryClientExecutor inMemoryClientExecutor = new InMemoryClientExecutor(dispatcher);
    }

    @Override
    public Class getObjectType() {
        return InMemoryClientExecutor.class;
    }

    @Override
    public boolean isSingleton() {
        return true;
    }

    private static Object unwrapProxy(Object bean) throws Exception {
        Object result = bean;
        /*
         * If the given object is a proxy, set the return value as the object
         * being proxied, otherwise return the given object.
         */
        if (AopUtils.isAopProxy(bean) && bean instanceof Advised) {
            Advised advised = (Advised) bean;
            result = advised.getTargetSource().getTarget();
        }
        return result;
    }
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top