The way forward for JakartaEE packages

Many of you might have read Mike Milinkovich’s post about the negotiations between the Eclipse Foundation and Oracle over the use of the javax.* package names.

https://eclipse-foundation.blog/2019/05/03/jakarta-ee-java-trademarks/

To give a short summary: Oracle is donating all the Code and IP they have. And this is a HUGE step for them, involving hundreds of developers and even more lawyers (hey, Oracle is a huge company, they do not do anything without a lawyer involved). So I also don’t want to buy into the blame game but I’m rather thankful that they did this!

One thing we all hoped would happen did not materialise though: Oracle doesn’t want us to change anything on packages starting with javax.*. That’s a pity but it’s not worth fighting.

In the following post I’d like to share my view about how we can go forward with JakartaEE from a purely technical perspective.

What options are on the table?

Since we are not allowed to change a bit of the signatures in javax.* we need to do it somewhere else. There has been a vote already quite some time ago. And this vote was in favour of using jakarta.* for new JakartaEE specs. So it make sense to also use this package for new features in existing specs.

Preface: All those options have some drawback and I’m still not sure myself what would be the best solution.

Option A: Extend as we need changes

In the first scenario we would keep all javax.* packages alive. And if we need to enhance some interface then we’d just extend it into a new interface in the jakarta.* namespace and add the methods and functionality there when new features get added.

For example if we look at the following class:

public interface javax.servlet.ServletRequest

In case we need some additional method in there we’d just extend this interface:

public interface jakarta.servlet.ServletRequest
  extends javax.servlet.ServletRequest {
    int someNewMethod();

The benefit would be that we do not need to touch servers. We also would be perfectly backward compatible – so no user code would need to change.

But of course it also comes with a few huge bummers:

1. We cannot add any additional attributes to annotations. And there is no extending of annotations in Java…  All we could do is to copy the annotation over to jakarta.* and enhance it there. And all frameworks have to lookup both annotations. This is really annoying.

2. Whenever we have interface hierarchies, then we it becomes slightly ugly. Think about javax.json.JsonValue and it’s sub interfaces like JsonStructure, JsonArray, JsonNumber, etc .
In this case an interface in jakarta.* would need to extend both the parent in jakarta and the corresponding javax class:

public interface jakarta.json.JsonNumber 
  extends javax.json.JsonNumber, jakarta.json.JsonValue 

3.) It becomes virtually impossible for abstract class hierarchies. Except I missed something.
In the old days (before default methods got introduced in Java8) abstract classes have been used instead of interfaces to allow adding methods without forcing users to implement them. We see this prominently in JSF for example in ResourceHandler.java and ResourceHandlerWrapper.java

javax.faces.application.ResourceHandlerWrapper extendsjavax.faces.application.ResourceHandler {

But how to map this to jakarta.*?

public abstract class 
  jakarta.faces.application.ResourceHandlerWrapper 
    extends javax.faces.application.ResourceHandlerWrapper 

and

public abstract class 
  jakarta.faces.application.ResourceHandler 
    extends javax.faces.application.ResourceHandler

But then jakarta.faces.application.ResourceHandlerWrapper is not an instance of jakarta.faces.application.ResourceHandler anymore 😦

Option B: Extend all interfaces and classes now

This is basically option A, but we do already extend all the interfaces in JakartaEE 8.
And of course they would for now all be empty.

The main benefit of this would be that users could migrate over all features from javax.* to jakarta.* without having to think about what is there and what not.

[See update 2019-05-07 for additional issues which popped up]

Option C: Replace all javax.* with jakarta.*

This is pretty much the most aggressive option. But it has some benefits as well. It would be a clean cut and while users would have to migrate, they only need to do it once. And the rules are really straight forward and clean. Just replace all javax.* imports with jakarta.*.

Of course this option also doesn’t come for free. in this cases it is not even the fault of JavaEE. There are still some JavaSE classes which reference classes which actually belong to JavaEE specifications. JSR-250 common-annotations (javax.annotation.*) is an example. Other nasty mix-ups are in the javax.security and java.sql area as shown in the following case:

public interface javax.sql.XAConnection extends PooledConnection { 
 javax.transaction.xa.XAResource getXAResource() throws SQLException;

Since javax.sql.XAConnection is not in JakartaEE but in SE we do not have any control over the return type. This will remain returning javax.tranxaction.xa.XAResource for some time…

What we might do is to do the reverse to Option A in such cases. By default we just migrate specs to jakarta.*. But in rare cases – as the one above – we extend the original javax types. That way we would at least allow to be upcast able.

How to migrate older applications?

Such a jakarta-only server could still serve old applications which use the javax.* APIs. In this case we would provide a javaagent which does a Class-transform and basically rewrites every JavaEE import to the corresponding JakartaEE import on the fly (in memory). Of course this is just a hack, but it might work out pretty fine.

We might also provide tools like a maven-plugin which dose the shade and transform during the build already.

Or containers also might op for doing this transformation when an app gets deployed to the server or on the first startup.

And what about the timeframe?

Initially it was concluded that JakartaEE 8 would be just a re-release of exact the same content as JavaEE 8.
With the only difference that it is now handled under the umbrella of the Eclipse Foundation, and not the JCP anymore.

Would this still hold true, then we would get a JakartaEE 8 with javax.* and JakartaEE 9 with jakarta.* packages. That might potentially be really confusing.

I personally would rather prefer to prepare the rename now and already ship JakartaEE 8 with the jakarta.* packages.

Final thoughts

All those ideas are just the beginning. We need to dig deeper, try ideas out and stick our heads together to come up with the best solution for everyone. There will most likely not be a perfect solution. But rest assured that we will not do stupid things!

Update 2019-05-07

I had a discussion with Emily Jiang on twitter during which I found one more potential problem for Option A and B: We must keep parameters for all interfaces which are expected to be implemented by users. Be it directly in form of e.g. javax.servlet.Servlet or javax.servlet.Filter or indirectly by having wrappers in user code.

Any input parameter would basically remain javax.* forever. Let’s look at an example. We migrate javax.servlet.Filter to jakarta.*:

public interface jakarta.servlet.Filter
  extends javax.servlet.Filter {..
     void doFilter(javax.servlet.ServletRequest request, 
                   javax.servlet.ServletResponse response,
                   javax.servlet.FilterChain chain) throws .. ;

I think it’s pretty obvious that we cannot change this signature, right? But on the other hand we might want to enhance the ServletRequest, so we’d need to introduce a jakarta.servlet.ServletRequest extends javax.servlet.ServletRequest. And since we cannot change the Filter method signature we’d have a big upcast party in all the code which touches it. Not a showstopper, but also certainly not nice.

Categorisation of APIs

I think we have a few different kind of APIs

  • Interfaces which must be implemented by the users.
  • Interfaces which are purely ‘used’, but never implemented in user code.
  • Interfaces which are mostly ‘used’, but sometimes wrapped in user code.

I’d say we should find a few of each and then play how they feel when assuming Option A, B and C before we decide which way to go.

Update 2019-05-10

I’ve already implemented quite a few spec APIs with the new package names (Option C style).

The APIs themselves are in the Apache Geronimo Spec Jakarta Branch Repository. This is work in progress and will be updated continuously.

I’ve also already migrated the core parts of the Apache OpenWebBeans CDI Container.

And finally we also already have an ok-ish branch for Apache Tomcat 10

It is certainly a lot of work to migrate to the new package space. But so far I did not hit any showstoppers!

About struberg
I'm an Apache Software Foundation member and Java Champion blogging about Java, µC, TheASF, OpenWebBeans, Maven, MyFaces, CODI, GIT, OpenJPA, TomEE, DeltaSpike, ...

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: