The concept of specification and implementation is really pretty basic software engineering concepts. Your specification is the high level design. To help understand, I just came up with a really simple example.
Say I want to have a parsing library. I know how I want to be able to use it. The only problem is that I am not very good at writing parsing code. So I create a high level specification, and I outsource the implementation. Here are the three classes that are part of the spec. They are all contained in one "API jar", say myparsers-api.jar
public interface Parser {
String[] parse(String s);
}
public interface ParserFactory {
Parser getBySpaceParser();
Parser getByCommaParser();
}
public class ParserDepot {
private static ServiceLoader<ParserFactory> loader
= ServiceLoader.load(ParserFactory.class);
public static ParserFactory getDefaultParserFactory() {
final List<ParserFactory> factories = new ArrayList<>();
loader.forEach(factories::add);
if (factories.isEmpty()) {
throw new IllegalStateException("No ParserFactory found");
}
return factories.get(0);
}
}
So at this point, I can actually code against this jar. If I were to uses it as is right now in another project, the project would compile just fine.
ParserFactory factory = ParserDepot.getDefaultParserFactory();
Parser parser = factory.getBySpaceParser();
String[] tokens = parser.parse("Hello World");
System.out.println(Arrays.toString(tokens));
So even though there is no implementation of this specification, I can still code against it, and compile against it. But when I try to actually run the program, it won't work, as there is no implementation. You can try to run this code, and you will get an IllegalStateException
(see the docs for ServiceLoader if you're unfamiliar with this pattern).
So I outsource the implementation to say a company called Stack Overflow. They get my myparsers-api.jar and they need to give me back an implementation. They would need to implement a ParserFactory
, and a couple of Parser
s. They might look something like this
public class SoByCommaParser implements Parser {
@Override
public String[] parse(String s) {
return s.split("\\s+,\\s+");
}
}
public class SoBySpaceParser implements Parser {
@Override
public String[] parse(String s) {
return s.split("\\s+");
}
}
public class SoParserFactory implements ParserFactory {
@Override
public Parser getBySpaceParser() {
return new SoBySpaceParser();
}
@Override
public Parser getByCommaParser() {
return new SoByCommaParser();
}
}
Now Stack Overflow gives me back a jar (say so-myparsers-impl.jar) with these three classes and the required META-INF/services file (per the ServiceLoader pattern), and now when I add the so-myparsers-impl.jar to my project and try to run it again, the program now works, because now it has an implementation.
This is exactly how the JAX-RS spec works. It only defines the high level design of how it should work. The classes, interfaces, and annotations that are part of that design are placed in an "API jar" just like my high level parsers are put into a jar. Implementations cannot alter these classes. All the classes that are part of the JAX-RS specification (version 2.x) are put into one single jar javax.ws.rs-api
. You can code against that jar, and your code will compile just fine. But there is nothing to make it "work".
You check out both the written specification and the classes defined by the specification and you will notice that the only classes included in the source code are those mentioned in the specification. But what you should notice is that the written specification doesn't mention anything at all about how it is supposed to be implementation. Take for example the following code
@Path("/test")
public class TestResource {
@GET
public String get() {
return "Testing";
}
}
@ApplicationPath("/api")
public class MyApplication extends Application {
@Override
public Set<Class<?>> getClasses() {
Set<Class<?>> classes = new HashSet<>();
classes.add(TestResource.class);
return classes;
}
}
Now the specification states that this is all we need to run a JAX-RS application in a servlet container. And that's all it says. It says nothing about how it all supposed to work. This is just how it is designed to work.
So what, is there some magic voodoo in Java that we don't know about that will make this Application
class start a server, and some hocus pocus that will make a @Path
annotated class automatically accept requests. No. Some body needs to provide the engine. The engine might be 20,000 lines of code just to make the above code work as specified.
That being said, Jersey is just the name of an implementation. It's like when I outsourced my parser implementation to Stack Overflow; The name Jersey itself is just the name of the project, just like Hadoop is a name of the project. In this case, what the project is, is an implementation of the JAX-RS specification. And because JAX-RS is just a specification, it means that anyone can implement it. If you wanted to, you could write your own implementation. As long as it works how it is defined to work in the written specification, then you can say that your code is an implementation of JAX-RS. There's more than just Jersey out there; you also have RESTEasy, which is another implementation.
As far as how Jersey implements the engine, that is way too broad. What I can do, is give you a high level overview of what happens behinds the scenes.
A JAX-RS application is defined to run inside of a servlet container. If you understand servlet containers and the servlet spec, then you'll know that the only way to handle requests is either by writing a HttpServlet
or Filter
. So if you want to implement JAX-RS then you need to able to handle requests either through a HttpServlet
or a Filter
. The ServletContainer
you mentioned, is actually both. So for Jersey, this is the "entry point" into the Jersey application, as far as request processing is concerned. It can be configured in a number of ways (I've leave that research to you).
And if you understand how to write your own servlet, then you know all you get is an HttpServletRequest
and HttpServletResponse
. You need to figure out what to do from there; get request info from the request, and send response info back out in the response. Jersey handles all of this.
If you really want to get into the gory details of what is going on under the hood, you will just need to to dig into the source code, starting from the entry point, the ServletContainer
. Be prepared to spend months on this to get a really good understanding of how it all works. It's not something that can be explained in one Stack Overflow post, if that's what you're expecting.