Skip to main content

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [List Home]
Re: [servlet-dev] Big ticket items for Servlet 6 / Jakarta EE 10?

Inline ...

Warning: this is all my opinions, based on supporting servlet-api over the past 15 years.
Both as a user of the servlet-api and as an implementer / committer of a Servlet API container (Jetty).
The opinions expressed here do not represent or imply anything from the Eclipse Jetty project's point of view.

On Thu, Aug 27, 2020 at 6:53 AM arjan tijms <arjan.tijms@xxxxxxxxx> wrote:
Hi,

A number of other specs in Jakarta have provided some ideas or roadmap items for their next major versions.

Until so far I don't think Servlet has provided any such ideas, although we do have a backlog of about 112 issues, which are mostly clarifications or small enhancements.

One of the pitched themes for Jakarta EE 10 is alignment, and for this theme I'd like to make a few proposals:

1. In cooperation with Jakarta REST (previously JAX-RS), see if we can define a subset of Servlet on which Jakarta REST can conveniently depend. At the moment most Jakarta REST implementations are based on Servlet anyway, but officially there's no such dependency.

I support a low level http API, emphatically.

Here's what I view it as ...
  • No WebApp concepts - no WAR, no Annotations, no WEB-INF, no descriptors, no fragments, no ServletContext, nada.
  • Programmatic Assembly of server behavior.
  • 100% Async behaviors - no Input/Output streams, no blocking behaviors of any kind, reduced threading needs (consider Channels, or ByteBuffers, perhaps even with JDK Flow API)
  • No request or response wrapping allowed.
  • Request and Response interception behaviors allowed (similar to Tomcat valves, and Jetty I/O interceptors, but formalized)
  • No request include/forward dispatching of any kind.
The existing Servlet API should be able to be built on top of this.


2. For in a Jakarta EE environment, and as a separate related new spec, define a CDI version of Servlet, for instance with the proposed package jakarta.servlet.cdi. This would define what a Servlet would look like as a pure CDI bean, and in addition would finally allow us to transfer the HttpServletRequest producer that's now in core CDI itself. 

Alternatively this can also be proposed as a completely independent spec, not using the jakarta.servlet package, and just building on Servlet (like, e.g. Jakarta Faces does).

From your description, this needs to be an independent spec,
Just like jakarta.servlet.jsp.

I've rewritten this section about a dozen times, to make it seem less hostile towards CDI, but frankly, any criticism of CDI in the past has always resulted in arguments, so I'll leave my last edit.
Any attempt to make servlet depend on CDI will cause an immediate schism in the servlet user-base.
It will become ("the clean servlet-api that works with my chosen technologies" vs "the forced CDI behaviors that I never use and cause me problems with my chosen technology stack")

Talking with various cloud providers about java server installations, the rate of use of CDI vs Other injection libs is extremely skewed away from CDI. (Spring dominates, but other libs like Guice are not that far behind, and even the "other" category surpasses CDI use by a huge factor).

Now for the pro-CDI part of my comments.
The Servlet API needs a better, more formalized, Injection layer that all CDI implementations, and even other libs can use.
(Other libs: spring, guice, various metrics libraries, audit libraries, etc.)
Right now, every library needs to write a custom, server specific (sometimes even server version specific), layer to hook into the Servlet API.

I think having a "Injectors" and/or "Decorators" layer in the servlet API could prove very useful, for everyone, all projects.
But this layer has 2 different needs/behaviors.
One is the pure Injection behavior, seen often with CDI, where existing instances are just injected with more values.
The other is the Decorator behavior, where the class is potentially wrapped with another implementation prior to it being used. (often seen with metrics libraries, and behavior validation libraries, and security audit libraries, and cloud behaviors)

This API should be passed ALL objects that are involved in the Servlet API.
Servlets, Filters, Various Servlet Listeners, ServletContainerInitializers, ServletOutputStream, ServletInputStream, HttpServletRequest, HttpServletResponse, Cookie, HttpSession, HttpUpgradeHandler, WebConnection, AsyncContext, MultipartConfig, Part, etc ...

Having a single API would be ideal, but it would probably be more useful as two different APIs with a clean lifecycle.
 

Thoughts?

Anything else that's big? Any of the existing issues we'd like to prioritize for Servlet 6?

Big on my list: REMOVE deprecated methods and concepts. 

The Servlet API is old, old beyond words, and maintaining an implementation of the API is increasingly difficult due to this cruft.
This removal should have happened in Jakarta EE 9 (with the namespace change).  The namespace change was big enough that removing deprecated things could have been done easier.  But that's just my personal opinion.

The next big thing is to break the API (yes, I said break the API) in certain select areas.
  • Deprecate RFC2616 behaviors entirely, we are on RFC7230 for HTTP/1.1
  • Upgrade jakarta.servlet.http.Cookie from it's RFC2109 support to RFC6265 with SameSite behaviors. 
  • HttpServletResponse.setContentType(String) should fail if an attempt to set anything other than a pure mime-type is used. (that's what HttpServletResponse.setCharacterEncoding(String) is for.
  • ALL HttpServletResponse methods that attempt to set/change things on the response headers after "committed" state has been reached MUST throw an exception (right now, they quietly fail, which is just awful)
  • Attempting to change the mimetype or charset on a HttpServletResponse after obtaining the .getWriter() MUST throw an exception indicating that the change was not applied due to the active Writer (the user of the API can choose to reset the buffer, set the headers, and refetch the writer though)
  • The ability to manage the registered mime-types for the webapp.
  • Mime type registration (programmatic or descriptor) should have an optional charset that will be applied to it when used.   This has a nuance though, as it's 3 states.  undefined_by_mimetype (meaning the use of the mime-type makes no change to the response charset), forced_on_response_headers (meaning the use of the mime-type forces a charset on the response, and it shows up on the Content-Type header) , implied_by_mimetype (meaning the use of the mime-type forces a charset on the response, but it never shows up on the Content-Type header).
  • HttpServletResponse needs an abort mechanism. (connection termination in HTTP/1.1 and GO_AWAY in HTTP/2 and HTTP/3)
  • HttpServletRequest and HttpServletResponse need HTTP Trailer support.
  • The behaviors for the various HttpServletRequest.getParameter() APIs need a uri-query only mode (no request body content is interrogated at all) - perhaps a new API
  • Programmatic (or annotated) behaviors (at the Servlet level for HTTP methods that allow automatic parsing of parameters or parts)
  • HttpServletResponse.getWriter() should have a either have a new ServletPrintWriter that throws IOException on failures (not this old-school System.out behavior where PrintWriter.write() can silently fail and you won't know unless you ask  PrintWriter.checkError())
  • HttpServletRequest needs informational APIs to know what state the Request Body is in (undefined, InputStream, or Reader)
  • HttpServletResponse needs informational APIs to know what state the Response Body is in (undefined, OutputStream, or Writer)
  • More allowed patterns in url-pattern definitions (uri-template lvl 1 like websocket? regex? multiple globs? etc)
  • Container Static File serving - formalize this, we know that the "Default" servlet handles this, but how do we register more static file sources? how do we let a Filter or Servlet decide that the current request should/could serve static files?  This should be something simple like boolean HttpServletResponse.serveStaticFile(StaticContext context, String pathInContext), where true means it is being done (committed), false means the file wasn't found in that context.
  • Finish flushing out the jakarta.servlet.annotation interface to finally allow the WEB-INF/web.xml descriptor to be entirely optional. (right now, some configuration is only possible in the WEB-INF/web.xml)
  • Any existing API that uses Strings for dealing with the filesystem should be changed to use java.nio.file.Path objects (eg: jakarta.servlet.Part.write(Path)) - not java.io.File! (Path is more flexible for virtual filesystems like zip/jar archives and environments with multiple Filesystem behaviors)
  • Error page registrations need a programmatic interface.
  • Eliminate Cross Context RequestDispatcher behaviors from the spec.  Forbid it. (the server implementers will thank you)
  • Response methods/classes that behave differently during INCLUDE (and FORWARD?) DispatcherType need to throw exceptions when an action they attempt is not allowed during INCLUDE dispatch (again, this silent / ignored behavior just introduces bugs and confuses the crap out of developers)
  • Ability to limit Filter introduction in FilterChain under more situations (currently limited to DispatcherType and url-pattern.  What about http methods/verbs? http version? request content-type? specific servlet packages? specific named servlets regardless of the url-pattern? etc..)
  • Overhauled Filter ordering (right now it's near impossible to get right with the mix of descriptors, annotations, fragments, dynamic registrations, etc) - A programmatic API during initialization of some sort that allows injection at specific points in the FilterChain that the existing DynamicRegistration API doesn't support.  
  • FilterGroups and spec defined groups with a specific call ordering within the FilterChain .. (eg: security/auth, upgrade, cache, data, conversion, audit, general) - that way a filter can specify that it needs to operate at a specific point in the list of FilterGroups.  And third party libraries can register at that level properly (eg: SSO, Response Caches, Security Audit Tooling, etc).
  • HTTP Exchange Listener API - Request creation, Request dispatching, Request state changes, Response header changes, Response state changes, Request read complete, Response write complete, etc..
  • Collapse the API, eliminate the Servlet, GenericServlet layers with it's non-HTTP bits and bobs.  It's only HTTP anymore.
  • The Async I/O API from Servlet 3.1 is fine, but it's a veritable mine-field of gotchas, few projects have successfully and correctly used it (at first, most that have stuck with it over the years have finally settled into a stable codebase of their usage).  We either need that layer cleaned up, overhauled, replaced, or a more fundamental layer like above.

As far as general features that Jakarta EE should introduce that will benefit many Jakarta EE projects (and users), including the Servlet API.

We need a static bytecode metadata standard, ala Jandex or Classgraph.

One where the need for ASM or BCEL is eliminated during runtime, and the precomputed (at compile time) bytecode scan is used instead. (from data present in a META-INF directory).
This would eliminate the multiple jar file scanning that occurs now, and standardize it across all of Jakarta EE.
And it would also ease the support when the JVM is on the module-path and the restrictions that the JVM places on the application (and containers) at that point.
It would also speed up initialization greatly!

- Joakim

Back to the top