I'm having troubles to wire Jersey with Jetty while trying to inject dependencies of my resouce. What I'm doing is:
public class MyApplication extends ResourceConfig {
public MyApplication() {
register(new MyBinder());
}
}
My binder simplified:
public class MyBinder extends AbstractBinder {
#Override
protected void configure() {
bind(ManagerImpl.class).to(Manager.class);
}
}
And my resource simplified:
#Path("test")
public class MyResource {
#Inject
Manager manager;
...
}
I tried this to wire all that together:
ServletContextHandler servletContextHandler = new ServletContextHandler(ServletContextHandler.NO_SESSIONS);
ServletContainer jerseyServletContainer = new ServletContainer(new MyApplication());
ServletHolder jerseyServletHolder = new ServletHolder(jerseyServletContainer);
jerseyServletHolder.setInitParameter("jersey.config.server.provider.classnames", MyResource.class.getCanonicalName());
servletContextHandler.setContextPath("/");
servletContextHandler.addServlet(jerseyServletHolder, "/*");
Server server = new Server(threadPool);
ServerConnector connector = new ServerConnector(server);
connector.setPort(httpPort);
server.setConnectors(new Connector[]{connector});
server.setHandler(servletContextHandler);
server.start();
However I keep receiving HTTP ERROR: 404
Any ideas how I could get it sorted?
Thanks
Ok, I also made it work without dropwizard and guice. For some reasons Jersey implementation doesn't include GuiceComponentProviderFactory since the version 2.XX. Otherwise it would be possible to do something like this:
Injector injector = Guice.createInjector( new ServletModule() { ...} );
IoCComponentProviderFactory ioc = new GuiceComponentProviderFactory( resourceConfig, injector );
Server server = JettyHttpContainerFactory.createHttpServer( BASE_URI + "services/", resourceConfig, ioc );
Since version 2.X they have integrated HK2 IoC framework with a GuiceBirdge, so you would need to mess around with HK2 and Guice:
GuiceBridge.getGuiceBridge().initializeGuiceBridge(aServiceLocator);
So I simply stick to HK2 for the moment having it wired all together in this way:
URI baseUri = UriBuilder.fromUri("http://localhost/").port(8800).build();
Server server = JettyHttpContainerFactory.createServer( baseUri, new MyApplication() );
server.start();
My ResourceConfig:
public class MyApplication extends ResourceConfig {
public MyApplication() {
register(new MyBinder());
register(MyResource.class);
}
}
So I simply missed to register my resources on top of registering my binder. So in that way I'm not using web.xml at all having nicely embedded jetty server.
Related
I want to add a ContainerResponseFilter and ContainerRequestFilter to my jetty-server. But when I try to add it, I get an error that the class is not good.
My jetty server-setup:
ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS);
context.setContextPath("/");
context.addFilter(CorsFilter.class, //Error here
"/*", EnumSet.of(DispatcherType.REQUEST));
Server jettyServer = new Server(8090);
jettyServer.setHandler(context);
ServletHolder jerseyServlet =
context.addServlet(ServletContainer.class, "/*");
jerseyServlet.setInitOrder(0);
jerseyServlet.setInitParameter("jersey.config.server.provider.classnames",
Login.class.getCanonicalName());
Starter.start(jettyServer);
and my filter:
public class CorsFilter implements ContainerRequestFilter, ContainerResponseFilter {
The error is that the method is not resolved.
Thanks!
ContainerRequestFilter and ContainerResponseFilter are not Servlet Filters, those are JAX-RS filters.
Register them with your ResourceConfig implementation.
Example:
#ApplicationPath("/")
public class MyApplication extends ResourceConfig {
public MyApplication() {
// Register resources and providers using package-scanning.
packages("my.package");
// Register my custom provider - not needed if it's in my.package.
register(CorsFilter.class);
// Register an instance of LoggingFilter.
register(new LoggingFilter(LOGGER, true));
...
}
}
Jersey normally uses HK2 dependency injection, but I would like to use Jersey with Dagger 2. Both Dagger and HK2 implement JSR 330, which I have taken as evidence that this should be possible without too much effort. I found ways to make Jersey work with CDI (e.g. Weld), Spring DI and Guice, but I can't find anything on Dagger.
To provide some context: I'm running a Grizzly–Jersey server in an SE environment, not in an EE container. My Maven project has com.google.dagger:dagger and org.glassfish.jersey.containers:jersey-container-grizzly2-http as dependencies, but not org.glassfish.jersey.inject:jersey-hk2, since I want to replace HK2 with Dagger.
The resource classes look like this:
#Path("/example")
public final class ExampleResource {
private final Dependency dependency;
#Inject
public ExampleResource(final Dependency dependency) {
this.dependency = Objects.requireNonNull(dependency);
}
#GET
#Produces(MediaType.APPLICATION_JSON)
public Example getExample() {
return this.dependency.giveExample();
}
}
And the Dagger component could e.g. be defined as follows:
#Component
public interface Application {
public ExampleResource exampleEndpoint();
public XyzResource xyzEndpoint();
// etc.
}
So that the main method would look similar to:
public final class Main {
public static void main(final String[] args) {
final Application application = DaggerApplication.create();
final URI baseUri = UriBuilder.fromUri("http://0.0.0.0/").port(80).build();
final ResourceConfig resourceConfig = new ResourceConfig();
// how to initialize `resourceConfig` using `application`?
final HttpServer httpServer = GrizzlyHttpServerFactory
.createHttpServer(baseUri, resourceConfig, false);
try {
httpServer.start();
} catch (final IOException ex) {
...
}
}
}
Running the application immediately results in an exception: IllegalStateException: InjectionManagerFactory not found. It seems that a Dagger implementation of this factory is needed.
My question is: how to integrate Dagger with Jersey?
You shouldn't think of it as "how to integrate dagger with jersey". Figure out how to setup jersey, then once you have that figured out, then you can worry about using dagger.
Here's (very roughly) how I would do it.
Create your own implementation of the ResourceConfig class.
#ApplicationPath("/service")
public class MyResourceConfig extends ResourceConfig {
#Inject
public MyResourceConfig(
#Nonnull final ExampleResource exampleResource) {
this.register(exampleResource);
}
}
Then create a module that sets up everything you need to create an HttpServer
#Module
public class MyServiceModule {
#Provides
#Singleton
#Named("applicationPort")
public Integer applicationPort() {
return 80;
}
#Provides
#Singleton
#Named("applicationBaseUri")
public URI baseUri(
#Named("applicationPort") #Nonnull final Integer applicationPort) {
return UriBuilder.fromUri("http://0.0.0.0/").port(applicationPort).build();
};
#Provides
#Singleton
public HttpServer httpServer(
#Named("applicationBaseUri") #Nonnull final URI applicationBaseUri,
#Nonnull final MyResourceConfig myResourceConfig) {
return GrizzlyHttpServerFactory
.createHttpServer(applicationBaseUri, myResourceConfig, false);
}
}
Then create your component that exposes the HttpServer. I typically like to make components that expose as little as possible. In this case, all you need to expose is the HttpServer.
#Singleton
#Component(modules = { MyServiceModule.class })
protected interface ServiceComponent {
HttpServer httpServer();
#Component.Builder
interface Builder {
// Bind any parameters here...
ServiceComponent build();
}
}
Then just go ahead and build your component, and start your HttpServer
public static void main(String[] args) {
final ServiceComponent component = DaggerServiceComponent.builder().build()
try {
component.httpServer().start();
} catch (Exception ex) {
// handle exception...
}
}
One more thing to note. I personally do not ever use the #Named("") annotation. I prefer to use a Qualifier. So you create a Qualifier annotation with a unique value. Then you can inject things like
#Provides
#Singleton
#MyUniqueQualifier
public String myUniqueQualifierProviderValue() {
return "something";
}
Then when injecting it
#Inject
public SomeClass(#MyUniqueQualifier #Nonnull final String myUniqueQualifiedValue)
If you use the #Named annotation you don't get compile time checks for conflicts or missing values. You would find out at run time that a value was not injected or then name conflicts with something else. It gets messy quick.
You need to implement an InjectionManagerFactory that will return an InjectionManager delegating to Dagger and have it registered as a service by putting an entry in META-INF/services, similar to the hk2 one here:
https://github.com/jersey/jersey/blob/master/inject/hk2/src/main/resources/META-INF/services/org.glassfish.jersey.internal.inject.InjectionManagerFactory
but referencing your own implementation.
I have a Spring MVC application and I'm trying to expose REST service using CXF (Jax-RS). I can't understand how to register my service and make it available. Here is my service:
#Path("/myservice/")
#Consumes(MediaType.APPLICATION_JSON)
#Produces(MediaType.APPLICATION_JSON)
public interface MyService {
#POST
#Path("start")
public String start(){
...........
}
}
So far I've managed to avoid any configuration file, only using annotations. So how do I expose my service without a config file? I couldn't find the information in the documentation.
Thanks
Here is the complete answer. Bits and parts can be found online, but nowhere had a complete answer that's easy to follow/implement.
I'll skip the maven part since it's pretty easy to figure it out.
Register CXF Servlet
#WebServlet(urlPatterns="/*")
public class CXFStartServlet extends CXFServlet {
}
Register all the Spring beans with #Path as a CXF service
#Configuration
public class MyCxfConfig {
#Autowired
private ApplicationContext ctx;
#Bean(name="cxf")
public SpringBus springBus(){
return new SpringBus();
}
#Bean
public Server jaxRsServer() {
LinkedList<ResourceProvider> resourceProviders = new LinkedList<ResourceProvider>();
for (String beanName : ctx.getBeanDefinitionNames()) {
if (ctx.findAnnotationOnBean(beanName, Path.class) != null) {
SpringResourceFactory factory = new SpringResourceFactory(beanName);
factory.setApplicationContext(ctx);
resourceProviders.add(factory);
}
}
JAXRSServerFactoryBean factory = new JAXRSServerFactoryBean();
factory.setBus(ctx.getBean(SpringBus.class));
factory.setProviders(Arrays.asList(new JacksonJsonProvider()));
factory.setResourceProviders(resourceProviders);
return factory.create();
}
}
Don't forget to import "MyCxfconfig" in your Spring config. That's all :)
I'm trying to implement my HK2 binding in Jersey, in a servlet / tomcat context.
I do, in a servlet which extends org.glassfish.jersey.servlet.ServletContainer :
#Override
public void init(ServletConfig config) throws ServletException
{
super.init(config);
// BinderInjection extends org.glassfish.hk2.utilities.binding.AbstractBinder
getConfiguration().register(new BinderInjection());
}
... but I get :
java.lang.IllegalStateException: The resource configuration is not modifiable in this context.
at org.glassfish.jersey.server.ResourceConfig$ImmutableState.register(ResourceConfig.java:270)
at org.glassfish.jersey.server.ResourceConfig$ImmutableState.register(ResourceConfig.java:218)
at org.glassfish.jersey.server.ResourceConfig.register(ResourceConfig.java:448)
at A_Servlet.init(RestServlet.java:45)
at org.apache.catalina.core.StandardWrapper.initServlet(StandardWrapper.java:1190)
So how can I do my own HK2 binding ?
Why this question ? (edit)
It's for EntityManager and JPA in Jersey.
With Netbeans, if I generate an AbstractFacade it put
#PersistenceContext(unitName = "myunit")
private EntityManager em;
... and :
#Override
protected EntityManager getEntityManager()
{
return em;
}
But, when I call the service, em is null. So I suppose it's #PersistenceContext which doesn't work ?
If I use the solution Tutorial: Put JPA in your Web App (tomcat, EclipseLink) and provide Rest JSON output all work like a charm, but I don't like use static variable private static EntityManagerFactory emf; for entity manager.
Thanks.
Below is an example where I am binding a Spring injected jersey resource to the Jetty Webserver. ResourceConfig utility is provided by Jersey. Hope this example helps.
p.s. -- restService is a Spring injected dependency
ResourceConfig config = new ResourceConfig(CustomRestService.class);
config.register(new AbstractBinder() {
#Override
protected void configure() {
bind(restService).to(CustomRestService.class);
}
});
restService.start();
ServletHolder apiServlet = new ServletHolder(new ServletContainer(config));
ServletHolder apiServlet = new ServletHolder(new HttpServletDispatcher());
servletContainer.addServlet(apiServlet, "/api/v1*//*");
How do I allow CDI injection of resources into restful web service resources? I am running on standard java using weld 2 (cdi), jersey (jaxrs), and grizzly (web server). Here is my simple web resource:
import training.student.StudentRepository;
import javax.inject.Inject;
import javax.ws.rs.*;
#Path("student")
public class StudentWebResource {
#Inject
private StudentRepository studentRepository;
#GET
#Path("count")
#Produces(MediaType.TEXT_PLAIN)
public Integer getCount() {
return studentRepository.studentCount();
}
}
And here is how I've got weld starting my simple web server:
public class Main {
public static void main(String[] args) throws Exception {
startCdiApplication();
}
public static void startCdiApplication() throws Exception {
Weld weld = new Weld();
try {
WeldContainer container = weld.initialize();
Application application = container.instance().select(WebServer.class).get();
application.run();
}
finally {
weld.shutdown();
}
}
}
And the code that I suspect will need to be modified to inform jersey to use weld for CDI inject resolution:
...
import org.glassfish.grizzly.http.server.HttpServer;
import org.glassfish.jersey.grizzly2.httpserver.GrizzlyHttpServerFactory;
import org.glassfish.jersey.jackson.JacksonFeature;
import org.glassfish.jersey.server.ResourceConfig;
public class WebServer implements Application {
/*
* startup the grizzly http server to make available the restful web services
*/
private void startWebServer() throws IOException, InterruptedException {
final ResourceConfig resourceConfig = new ResourceConfig().packages("training.webservice").register(new JacksonFeature());
final HttpServer server = GrizzlyHttpServerFactory.createHttpServer(getBaseUri(), resourceConfig);
server.start();
Thread.currentThread().join();
}
...
#Override
public void run() throws IOException, InterruptedException {
startWebServer();
}
}
After seeing this stackoverflow post, I implemented the following solution. Not sure if it is the best route to take, but it worked.
I created an hk2 Binder and registered the Binder:
public class WebServiceBinder extends AbstractBinder {
#Override
protected void configure() {
BeanManager bm = getBeanManager();
bind(getBean(bm, StudentRepository.class))
.to(StudentRepository.class);
}
private BeanManager getBeanManager() {
// is there a better way to get the bean manager?
return new Weld().getBeanManager();
}
private <T> T getBean(BeanManager bm, Class<T> clazz) {
Bean<T> bean = (Bean<T>) bm.getBeans(clazz).iterator().next();
CreationalContext<T> ctx = bm.createCreationalContext(bean);
return (T) bm.getReference(bean, clazz, ctx);
}
}
Then modified the ResourceConfig instantiation from above to:
final ResourceConfig resourceConfig = new ResourceConfig()
.packages("training.webservice")
.register(new JacksonFeature())
.register(new WebServiceBinder());
The selected answer dates from a while back. It is not practical to declare every binding in a custom HK2 binder.
I just had to add one dependency. Even though it was designed for Glassfish it fits perfectly into other containers. I'm using Tomcat / Grizzly.
<dependency>
<groupId>org.glassfish.jersey.containers.glassfish</groupId>
<artifactId>jersey-gf-cdi</artifactId>
<version>2.14</version>
</dependency>
Here is an example with JerseyTest (same principle if you run it from a main method). I just had to declare a dependency on weld-se and declare a Weld container before instantiating my resources - as you also did - and it works out of the box.
public class GrizzlyTest extends JerseyTest {
private Weld weld;
private WeldContainer container;
#Override
protected Application configure() {
weld = new Weld();
container = weld.initialize();
return new ResourceConfig(MyResource.class);
}
#Test
public void test() {
System.out.println(target("myresource").request().get(String.class));
}
#After
public void after() {
weld.shutdown();
}
}
Since at least Weld 2.2.0.Final there is no need to mess up with HK2 Binder.
As official Weld documentation states you just need to register org.jboss.weld.environment.servlet.Listener. Code snipped from doc:
public class Main {
public static void main(String[] args) throws ServletException, LifecycleException {
Tomcat tomcat = new Tomcat();
Context ctx = tomcat.addContext("/", new File("src/main/resources").getAbsolutePath());
Tomcat.addServlet(ctx, "hello", HelloWorldServlet.class.getName());
ctx.addServletMapping("/*", "hello");
ctx.addApplicationListener(Listener.class.getName());
tomcat.start();
tomcat.getServer().await();
}
public static class HelloWorldServlet extends HttpServlet {
#Inject
private BeanManager manager;
#Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("text/plain");
resp.getWriter().append("Hello from " + manager);
}
}
}
Above servlet listener manages the whole lifecycle of the Weld container. So there is no need to:
Weld weld = new Weld();
WeldContainer container = weld.initialize();
UPDATE
As #EdMelo pointed out, Grizzly HTTP server is not a fully compliant Servlet container. I didn't know this, thanks for this hint. So I'm not sure, if my answer still applies here.