When it comes to deploying REST web services with an embedded server such as Jetty, one would typically go about accomplishing it by specifying the WAR file in Jetty or running it from its exploded source components.

However, I wanted to avoid even the slightest hint of WAR files and web.xml files and deploy microservices that are as similar to POJOs as possible. After fiddling around with Jetty and Jersey, I’ve managed to come up with a simple way to deploy services that’s almost like plain old Java. In fact, I find that it’s much more pleasant to work with pure Java as I don’t have to worry about specifying pesky classes and configuration files.

Imagine that we have a simple resource:

package org.microservice;

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;

@Path("/test")
public class HelloWorldResource
{
	@GET
	@Produces(MediaType.TEXT_PLAIN)
	public String helloWorld()
	{
		return "Hello World!";
	}
}

Next, we just need the following main class and we’re done:

package org.microservice.runner;

import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHolder;
import org.eclipse.jetty.util.thread.QueuedThreadPool;

import com.sun.jersey.spi.container.servlet.ServletContainer;

public class HelloWorldService
{
	public static void main(String[] args) throws Exception
	{
		try
		{
			Server server = new Server(8081);
			ServletHolder servletHolder = new ServletHolder(ServletContainer.class);

			servletHolder.setInitParameter("com.sun.jersey.config.property.resourceConfigClass",
					"com.sun.jersey.api.core.PackagesResourceConfig");
            // IMPORTANT: you have to specify the package where your resources are located in order for Jetty to pick them up
			servletHolder.setInitParameter("com.sun.jersey.config.property.packages", "org.microservice");
                        
            // comment out to hide debug information
			servletHolder.setInitParameter("com.sun.jersey.config.feature.Debug", "true");
			servletHolder.setInitParameter("com.sun.jersey.config.feature.Trace", "true");
			servletHolder.setInitParameter("com.sun.jersey.spi.container.ContainerRequestFilters",
					"com.sun.jersey.api.container.filter.LoggingFilter");
			servletHolder.setInitParameter("com.sun.jersey.spi.container.ContainerResponseFilters",
					"com.sun.jersey.api.container.filter.LoggingFilter");

			ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS);
			context.setContextPath("/");
			context.addServlet(servletHolder, "/*");

			server.setHandler(context);

			QueuedThreadPool queuedThreadPool = new QueuedThreadPool(10);
			queuedThreadPool.setName("ApiServe");
			server.setThreadPool(queuedThreadPool);

			server.start();
			server.join();
		}
		catch (Exception e)
		{
			System.out.println(e.getMessage());
		}
	}
}

Once you’ve exported it out as a runnable .jar file, you can start your lightweight microservice with

$ java -jar <your_jar_filename>.jar