JAX-RSをやってみる (13) - Refの依存性注入に関して -
前回も記述したけど、JspTemplateProcessorでは
final class JspTemplateProcessor extends AbstractTemplateProcessor<String> {
@Inject
private Provider<Ref<HttpServletRequest>> requestProviderRef;
@Inject
private Provider<Ref<HttpServletResponse>> responseProviderRef;
みたいになっとる訳で、テストで使用する際にあたってそういうところの依存性の注入の解決がうまくいかないのがあったので普通に@Contextで注入する的な事をしてましたけど、なんとか出来たっぽいので
ThymeleafTemplateProcessor.java
package sample;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.Reader;
import java.io.Writer;
import java.util.HashMap;
import java.util.Map;
import javax.inject.Inject;
import javax.inject.Provider;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.ws.rs.core.Configuration;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.MultivaluedMap;
import org.glassfish.jersey.internal.util.collection.Ref;
import org.glassfish.jersey.server.mvc.Viewable;
import org.glassfish.jersey.server.mvc.spi.AbstractTemplateProcessor;
import org.jvnet.hk2.annotations.Optional;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.thymeleaf.TemplateEngine;
import org.thymeleaf.context.WebContext;
import org.thymeleaf.templateresolver.ClassLoaderTemplateResolver;
public class ThymeleafTemplateProcessor extends AbstractTemplateProcessor<String> {
@Inject
Provider<Ref<HttpServletRequest>> requestRef;
@Inject
Provider<Ref<HttpServletResponse>> responseRef;
ServletContext servletContext;
@Inject
public ThymeleafTemplateProcessor(Configuration config, @Optional ServletContext servletContext) {
super(config, servletContext, "thymeleaf", "html");
this.servletContext = servletContext;
}
@SuppressWarnings("unchecked")
@Override
public void writeTo(String templateReference, Viewable viewable,
MediaType mediaType, MultivaluedMap<String, Object> httpHeaders,
OutputStream out) throws IOException {
try(Writer writer = new OutputStreamWriter(out)) {
Object o = viewable.getModel();
Map<String, Object> stash;
if (o instanceof Map) {
stash = (Map<String, Object>)o;
} else {
stash = new HashMap<String, Object>();
if (o instanceof Exception) {
stash.put("error", o);
} else {
stash.put("it", o);
}
}
WebContext context = new WebContext(
requestRef.get().get(),
responseRef.get().get(),
servletContext
);
context.setVariables(stash);
TemplateEngine engine = new TemplateEngine();
engine.setTemplateResolver(new ClassLoaderTemplateResolver());
engine.process(templateReference, context, writer);
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
protected String resolve(String templatePath, Reader reader) throws Exception {
return templatePath;
}
}
的な感じで、テスト時に依存性を注入する必要があるのが
- Provider>
- Provider<Ref<HttpServletResponse>>
- @Optional ServletContext
以上の3つの依存性の注入の解決が必要になるはず
HomeTest.java
package sample.controller;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.ws.rs.core.Application;
import org.glassfish.hk2.api.Factory;
import org.glassfish.hk2.api.TypeLiteral;
import org.glassfish.hk2.utilities.binding.AbstractBinder;
import org.glassfish.jersey.internal.inject.ReferencingFactory;
import org.glassfish.jersey.internal.util.collection.Ref;
import org.glassfish.jersey.test.JerseyTest;
import org.junit.Test;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.mock.web.MockServletContext;
import sample.SampleApplication;
import static org.junit.Assert.*;
import static org.hamcrest.Matchers.*;
public class HomeTest extends JerseyTest {
MockHttpServletRequest request = new MockHttpServletRequest();
MockHttpServletResponse response = new MockHttpServletResponse();
@Override
protected Application configure() {
return new SampleApplication()
.register(new AbstractBinder() {
@Override
protected void configure() {
bindFactory(
ReferencingFactory.<HttpServletRequest>referenceFactory(request)
).to(new TypeLiteral<Ref<HttpServletRequest>>() {});
bindFactory(
ReferencingFactory.<HttpServletResponse>referenceFactory(response)
).to(new TypeLiteral<Ref<HttpServletResponse>>() {});
bindFactory(new Factory<ServletContext>() {
@Override
public ServletContext provide() {
return new MockServletContext();
}
@Override
public void dispose(ServletContext instance) {
}
}).to(ServletContext.class);
}
});
}
@Test
public void test1() {
String response = target("/sample/test1").request().get(String.class);
assertThat(response, containsString("hoge"));
}
}
っていう感じでReferencingFactoryを使ってやれば良い模様