gwtproject / gwt

GWT Open Source Project
http://www.gwtproject.org
1.51k stars 372 forks source link

No support for Jakarta EE 9 #9727

Closed mkosem closed 9 months ago

mkosem commented 3 years ago

GWT version: 2.9.0 Browser (with version): Firefox 87.0 Operating System: Linux


Description

GWT's servlet underpinnings make use of the javax.servlet.* packages, which are not supported on the Jakarta EE 9 API set (or by implementors of that spec - Tomcat 10.0, etc.). The new API version includes a wholesale repackaging, include no provisions for backwards compatibility, and it appears to be discouraged (if not outright impossible) to mix old and new APIs.

Will a forthcoming GWT version provide support for these new APIs and the platforms implementing them?

Steps to reproduce

Attempt to build and run a GWT application on a Jakarta EE 10.0 application server platform.

Dzek commented 3 years ago

It would be really nice to see a Jakarta EE compatible version of GWT in the near term. Would the Eclipse Transformer Project help in any way and can it be run against the existing GWT 2.9.x binaries?

niloc132 commented 2 years ago

I've been working with a gradle plugin that can transform a dependency on the fly using the linked Eclipse Transformer project, and while it is probably overkill, I've found it to do the job. It shouldn't be too difficult to add an additional set of server artifacts (just gwt-servlet and requestfactory-server, right?) to the build to support jakarta-servlet packages going forward.

Is that something that either of you would be interested in picking up?

jnehlmeier commented 2 years ago

I guess the transformer does a simple import rewrite in class files? So it might only be useful for Jakarta EE 9 given it has no API changes to Jakarta EE 8 which in turn has no API changes to Java EE 8 (it is just package renaming). However as soon as Jakarta EE 10 is released the GWT build might need to be changed again and code manually duplicated and adjusted because of potential API changes?

jnehlmeier commented 2 years ago

Basically I am not sure if that transformer is a good long term decision for GWT 2.x, even though it might be an easy one now.

niloc132 commented 2 years ago

I agree that this is probably a stopgap, though it would surprise me a bit to learn that the API would change in considerable ways. Checking out the current status of jakarta servlet 6.0 (which appear to be the next release), there are deprecated members being removed, but all have been deprecated since 2.x or so. If there are planned removals, we will need to keep an eye on that and probably maintain a different set of code as you suggest.

https://github.com/eclipse-ee4j/servlet-api/commits/master/api/src/main/java/jakarta/servlet/http

mduggen commented 1 year ago

Any news on supporting Jakarta EE 9/10? More and more frameworks do the hard cut and it will become a problem soon.

werthdavid commented 1 year ago

Struggling with this as well... Upcoming Spring 6 / Spring Boot 3 will be based on Jakarta so GWT doesn't work with that anymore.

ajkyffin commented 1 year ago

I've managed to build the user and servlet jars against the Jakarta 10 API and they work with the limited testing I've done so far. See https://github.com/ajkyffin/gwt (which includes https://github.com/gwtproject/gwt/pull/9777 and https://github.com/gwtproject/gwt/pull/9780 to build with Java 11) & https://github.com/ajkyffin/tools. I haven't managed anything with the dev stuff - I'm only using gwt-user.jar and gwt-servlet.jar.

niloc132 commented 1 year ago

We definitely would need to land #9777 and #9780 before this feature could go in, and also before we can finish Java 11 JRE emulation (specifically tests), and before we can look into Java 17 language support (which requires minimum of Java 11). Once those are reviewed and landed, your patch probably makes sense. The code itself is ready for review, and the javadoc samples should be checked too, to be sure they are what we want.

But I might suggest instead of changing gwt-servlet etc that we produce a new jar, gwt-jakarta-servlet, so that existing projects who arent planning on updating can stay on javax for now, without duplicating each file and maintaining two copies. As in your patch, it can probably be achieve just by replacing javax.servlet with jakarka.servlet and building to a new jar, plus a new pom.

At some point we'll probably cut over and change dev mode to use jakarta and a non-EOL Jetty version, but as this is only for local use I don't think we're in a big hurry to switch (and projects should generally avoid hosting their own content in the dev mode server anyway). That in turn probably means that gwt-user itself shouldn't need to be updated either, at least right away, as it should never be on the server classpath anyway.

So please, if you're interested in this work, let's get a few other PRs reviewed and merged, then this can move forward.

werthdavid commented 1 year ago

What can I do to help you?

werthdavid commented 1 year ago

I've been playing around with @ajkyffin branch, looks good so far. I think providing a gwt-user-jakarta.jar is the way to go. With spring going to Jakarta I guess the whole Jakarta thing will be going forward a lot now.

What I "worry" about is the gwt-dev. It uses quite a lot outdated dependencies that need an upgrade and not just an update..

niloc132 commented 1 year ago

@werthdavid As help goes, we have a number of PRs that need reviews to move forward - for the ant changes, no one really has a deep understanding of the hows/whys of the code, so I would ask mostly for an extra set of eyes to look for dumb mistakes, ask questions about potential mistakes, and confirm processes were followed where it isn't obvious to you. For the Javadoc changes, I have no experience with much of the new APIs (java9+), though I do have experience with Elements and Mirrors from annotation processors. If you (or someone you know who can take a little time) do have experience there all the better, otherwise as above - I just want to avoid a "rubber stamp" of "sure, I guess its fine", but make sure that the code is doing what we expect, and future-us won't have to deal with headaches from new odd behaviors being added.

I am only mildly worried about gwt-dev personally - the jar should never be deployed as part of an application (at least not without being very aware of how it is built and what it contains), but only should be used as part of a build process running on trusted code, so risks, while non-zero, are small. Keeping backwards compatibility with old projects that cannot update to new conventions remains important, since other fixes to the compiler and runtime will enable existing projects to still work on newer browsers, but breaking those projects risks leaving them stranded. On the other hand, current best practices suggest that we discourage running a project's own server-side code inside of dev mode, which makes this a moot point for projects looking to update and take on the jakarta.servlet migration. They still may need requestfactory/rpc/etc code to be updated and modernized, but that all lives in requestfactory-server.jar and gwt-servlet.jar.

(Note that those best practices are not well documented in the gwtproject.org docs, and we're in need of overhauling old examples. However, the new gwt-maven-plugin strongly encourages this approach, and the majority of projects I'm aware of use maven over gradle/ant).

werthdavid commented 1 year ago

What I meant with worry is not security issues. It's more the question if we can ever manage to get this thing running with Jakarta. Currently Jetty 9 is used to start the code-server. With Jakarta we need Jetty 11. Also there are lots of other dependencies like forked Hibernate and stuff that rely on javax. I first thought @ajkyffin branch is working but that doesn't really work either, it also compiles against javax.

ajkyffin commented 1 year ago

I had a quick attempt at updating Jetty, but there were a lot of build failures due to classes and methods that had been removed, so I gave up on gwt-dev and only did the user/servlet (which is all I need).

werthdavid commented 1 year ago

I can't get it running with your gwt-user and gwt-servlet @ajkyffin . There are still javax.validation imports used so GWT-compile fails in my sample project that uses Spring Boot 3 RC2

tbroyer commented 1 year ago

Why would Spring Boot (server-side) influence GWT Compile (client-side), or the other way around? If you have everything inside the same project, sharing the same classpath, then split them into client and server (and probably shared) projects so each can have its independent classpath, without polluting the others.

werthdavid commented 1 year ago

Yup, that's the only solution I see atm

tbroyer commented 1 year ago

Fwiw, I've been preaching it for more than 10 years already: https://blog.ltgt.net/announcing-gwt-maven-archetypes-project/

werthdavid commented 1 year ago

It does make sense! We do have lots of smaller and bigger modules that contain frontend, backend & shared code in one maven module. It is quite some overhead to separate each module but I don't see an alternative. Knowing that separation would've made sense in the first place but you know how it is if it has to be developed fast..

vals-productions commented 1 year ago

since 2.10.0 is already out it might make sense to have a simple release of 2.11.0 with (mostly) the change of being based on jakarta?

Spring 6 switches to jakarta packaging and that will drive industry towards new packaging in a strong way.

2.10.x and 2.11.x could coexist in parallel for some time in case critical fixed would be necessary.

niloc132 commented 1 year ago

@vals-productions there has been some discussion of this over at https://groups.google.com/g/google-web-toolkit-contributors/c/SuhBveCHoFA, but the short version is that backward compatibility remains important so that existing stable projects that are not under active development don't need rewrites to move to a new compiler version (so as to support new browsers, run under new JDKs, fix security issues). As discussed there, there are many other things we could consider already dropping support for as well (legacy dev mode, selenium,. java 8 and for that matter 11, IE 11 and non-chromium Edge).

With a larger development team, we could aggressively backport fixes, but as you can see in this thread, we're struggling to even get reviewers for code as it is written (though we're never wanting for release testers, which I always appreciate when we cut a release). As such, unless we have a plan to support 2.10.x for the next several years and permit 2.11 to drop any and all "legacy" code, I'm not sure that path is viable.

I will take a short stab at generating sources for a gwt-servlet-jakarta.jar tomorrow, under the assumption that modern projects who might consider this can also take a modular approach (no mixing client and server code, so no need for any javax->jakarta in gwt-user, so no need to work on validation just yet). If it goes well, that would be an additional release artifact, with no breaking changes for projects that aren't ready for that update.

anowac01 commented 1 year ago

My project(s) are definitely not "modern", but we are under active development and try to keep our appservers / dependencies somewhat up to date, so Jakarta EE 9/10 is in our future somewhere. All of our GWT projects have client and server code intermixed in a single war, with lots of classes used on both client and server, passed back and forth over GWT-RPC services. I'm a bit concerned about disentangling all that (particularly since we aren't very disciplined about distinguishing client-only vs. shared code since that has not really mattered before).

I'm looking into some of the links upthread to try to understand the implications of the "modular approach" being advocated, but they all seem to be oriented toward Maven projects, while we're still using Ant as our build tool. Are there any guides / examples out there that don't depend on Maven?

niloc132 commented 1 year ago

I've made a rough draft of how this could look for gwt-servlet, with a few caveats: sources and javadoc are still wrong, and the requestfactory-server jar hasnt been updated in the same way.

To try this out, please add https://repo.vertispan.com/gwt-snapshot/ as a repository for your maven/gradle project, and depend on org.gwtproject:gwt-servlet-jakarta:2.11.0-jakarta-SNAPSHOT from your server project instead of gwt-servlet - the same version will work to get gwt-user and gwt-dev as well, but those still use javax.servlet (at least for now). You can see the deployed jar here: https://repo.vertispan.com/gwt-snapshot/org/gwtproject/gwt-servlet-jakarta/2.11.0-jakarta-SNAPSHOT/

Note that this uses the v5 jakarta.servlet api, despite v6 being latest - v4 is still javax.servlet, and v6 requires a minimum of something higher than Java 8, so can't presently build here (watch #9780 to lift that limitation).

I've created a modular-webapp project using the ltgt maven archetype. I swapped out the jetty 9.x plugin for jetty 11.x, to ensure that jakarta.servlet would be required, and removed the javax.servlet api jars in favor of jakarta.servlet. https://github.com/Vertispan/jakarta-servlet-gwt-app

--

@anowac01 The short version is that anything used exclusively by the server should be in one module/project/sourceset, anything used exclusively by the client should be in another, and anything used by both should be in a third, which the first two depend on. There are at least two benefits you may see from this (not counting "hmm, which FooBar should I import here?"): more, smaller source sets tend to compile faster (and potentially in parallel with each other), and any steps you can take to avoid accidentally feeding the GWT compiler something that it can't process will improve incremental performance. For the latter point, ensure you are passing -strict to SDM and the compiler, to avoid it permitting compile errors that don't affect your output - these can still impact build times by giving the compiler extra work to do.

We could go further and rewrite all javax.servlet in one pass, but again, existing projects that still don't have a plan to move to jakarta then have to pay that maintenance burden early (or at all). I acknowledge that you are paying a different cost due to this decision, and I'm not sure how to balance this. One option could be to repeat the work I've done so far and apply it to all jars, so that gwt-user, gwt-dev, gwt-codeserver all have these changes made as well, with two caveats: Jetty will need to be updated (hopefully will be drop-in, but possibly not), and javax.validation will not be updated (as it is not supported in GWT itself at this time).

CrushaKRool commented 1 year ago

I am only mildly worried about gwt-dev personally - the jar should never be deployed as part of an application (at least not without being very aware of how it is built and what it contains), but only should be used as part of a build process running on trusted code

I wish it was that easy. Not sure whether this counts as weird edge case, but with the GWT Eclipse Plugin, we occasionally run into problems due to all the outdated third-party classes that are bundled in the gwt-dev because they involuntarily get mixed into the actual runtime classpath. For example even using newer versions of Hibernate becomes problematic because some of the annotation classes in the gwt-dev are too old and are missing certain properties, preventing us from using these annotations in beans that are shared between server and client. We'd just get a NoSuchMethodException at runtime when Hibernate tries to do its thing. This wasn't as much of an issue when the gwt-dev contents were still somewhat up-to-date, but it became more noticeable as more and more of the included libraries started changing their API in newer versions.

To be fair, this problem only exists in the IDE, because here the GWT Eclipse Plugin adds the GWT SDK as a separate classpath container that takes precedence over the Gradle classpath container (so we can't even fix the annotations by including newer external dependencies). If we were to force the Gradle classpath container to take precedence over the GWT SDK, then we run into other GWT compilation issues (perhaps because our Gradle classpath contains a newer version of the ECJ compiler than the one used by GWT). Outside of Eclipse, we can use Gradle to properly separate the GWT SDK during the WAR build from the remaining classes that are deployed into production, so there are no issues once we actually deploy the app. And IntelliJ users don't seem to have this problem either, probably because it does not have the concept of different classpath containers.

Though it makes me wonder what tooling other people are using to develop their GWT apps. Is nobody else using the GWT Eclipse Plugin or are we simply using it wrong? (At one point a colleague was even suggesting that we should build our own customized version of the GWT SDK with updated dependencies to work around the issue, but that's a whole different can of worms that I'd like to keep unopened.)

eliasbalasis commented 1 year ago

Though it makes me wonder what tooling other people are using to develop their GWT apps. Is nobody else using the GWT Eclipse Plugin or are we simply using it wrong? (At one point a colleague was even suggesting that we should build our own customized version of the GWT SDK with updated dependencies to work around the issue, but that's a whole different can of worms that I'd like to keep unopened.)

We also have quite a few GWT projects here, using GWT Eclipse Plugin consistently and quite successfully so far, but up to GWT 2.9.0 only.

We are looking forward to the next release of GWT Eclipse Plugin which is expected to support GWT 2.10.0

In our experience, when using GWT Eclipse Plugin, it is best to run simpler variants of the actual UI apps, or keep them as simple as possible so that they can still run on Jetty even with an altered classpath.

jnehlmeier commented 1 year ago

@CrushaKRool Co-workers use Eclipse + GWT Eclipse Plugin but never run/start the app using GWT Eclipse Plugin. It is only used for code assist, etc. The project is built using Gradle and configured by Eclipse itself via Gradle and I think only the dependencies defined in Gradle end up on the projects class path.

Every developer uses Docker and we have a fixed set of docker images that replicate our production environment. So developers do not have to configure the app server on their own. All they do is mounting a local folder into the running container (e.g. Host: /Users/me/webapp -> Container: /var/lib/jetty/webapps/) and then use a custom Gradle task that copies the produced *.war file into that folder, e.g. gradlew copyWar -Pdest=/Users/me/webapp. The app server then deploys the file.

It is generally recommend to install/manage/use your own application server / servlet container. The bundled jetty is only meant to be used for small demo like apps to get quickly started. All headaches will go away once you fully decouple server code deployment from GWT Eclipse plugin. IMHO it is a real benefit to do so since development and production environment are the same then. That way you spot server related issues early during development. Or imagine you don't even use Jetty/Tomcat in production but instead maybe WildFly. Why would you then develop using Jetty/Tomcat?

The point is the more complex your project the less you should rely on the bundled server provided by GWT and instead use your own.

For Hibernate Validation there is a dedicated project that provides newer emulations: https://gitlab.com/ManfredTremmel/gwt-bean-validators

CrushaKRool commented 1 year ago

Thanks, it's nice to see some other perspectives and potential best practices on how to develop. We don't actually use the bundled Jetty from the plugin, but we still use Eclipse to launch our own embedded Jetty (from Gradle dependencies) along with our server code. Then we use a second launcher in Eclipse to start GWT in SuperDevMode but without the embedded Jetty. We can use either the browser's dev tools for debugging or debug in Eclipse via the SDBG (though it's more likely to desync). Wouldn't deploying the full WAR to a server require to precompile the full app every time you change something, though? Our GWT app is pretty big (though modularized, so we can benefit from the JIT compilation and incremental builds when running it via SuperDevMode) and we'd be looking at compile times of ~20-30 minutes for a minimal set of localizations and user agent permutations.

Anyway, didn't want to hijack the topic. Just pointing out that the outdated third-party dependencies in the gwt-dev JAR can actually be problematic. And Hibernate was just one example. We've also had issues with certain Spring modules.

lofidewanto commented 1 year ago

From this thread: https://github.com/gwtproject/gwt/issues/9727#issuecomment-1332854391

My collegue tried the artifact gwt-servlet-jakarta-2.11.0-jakarta.jar (https://repo.vertispan.com/gwt-snapshot/org/gwtproject/gwt-servlet-jakarta/2.11.0-jakarta-SNAPSHOT/) with the Spring Boot 3 and it seems to work.

Spring Boot 3 uses only jakarta.*, please see: https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-3.0-Migration-Guide

So, it's good if we could have:

  1. the gwt-servlet-jakarta-[VERSION]-jakarta-[VERSION].jar for jakarta.*
  2. the gwt-servlet-[VERSION].jar for javax.*

Any ideas to make this possible?

I don't think that we need to do this for the rest of GWT artifacts since the rest of them are for development?

lofidewanto commented 1 year ago

Thanks, it's nice to see some other perspectives and potential best practices on how to develop. We don't actually use the bundled Jetty from the plugin, but we still use Eclipse to launch our own embedded Jetty (from Gradle dependencies) along with our server code. Then we use a second launcher in Eclipse to start GWT in SuperDevMode but without the embedded Jetty. We can use either the browser's dev tools for debugging or debug in Eclipse via the SDBG (though it's more likely to desync). Wouldn't deploying the full WAR to a server require to precompile the full app every time you change something, though? Our GWT app is pretty big (though modularized, so we can benefit from the JIT compilation and incremental builds when running it via SuperDevMode) and we'd be looking at compile times of ~20-30 minutes for a minimal set of localizations and user agent permutations.

Anyway, didn't want to hijack the topic. Just pointing out that the outdated third-party dependencies in the gwt-dev JAR can actually be problematic. And Hibernate was just one example. We've also had issues with certain Spring modules.

Actually the best practice are:

  1. Always to separate the server and client module, in this case you never have such a problem, see my example in this article: https://bit.ly/DynamiteDuo

  2. You actually never need a plugin in any IDEs, just user Chrome for debugging and you won't have any problem with any tools.

sparsick commented 1 year ago

For me, the artifact https://repo.vertispan.com/gwt-snapshot/org/gwtproject/gwt-servlet-jakarta/2.11.0-jakarta-SNAPSHOT/ works in our Spring Boot 3 app.

Do you have plans to release it soon? Currently, it is a blocker for us to go further with our migration to Spring Boot 3.

How I can help to go further with this issue?

Thanks a lot.

niloc132 commented 1 year ago

Thanks for your feedback.

The branch can be found in my fork at https://github.com/niloc132/gwt/tree/9727-jakarta-servlet-support - the description of the first commit outlines some work that needs to be done to land this.

https://github.com/niloc132/gwt/commit/aa27cbc67a99d594f8bf48b8d89cb6aa0865c89e

Off the top of my head, we should also look into what other packages need changing as part of the javax->jakarta migration - validation perhaps? That would only apply to the server-side components of requestfactory, but still may need to be done.

sparsick commented 1 year ago

@niloc132 Thanks for the list. I will have a look on it. Maybe, I can help with some subtask.

sparsick commented 1 year ago

Hi @niloc132,

I opened two PR to go further with this topic.

It would be great if you could review them and give some feedback, when I run in the wrong direction.

I like to help more, but I have an understanding problem: I'm not sure what I have to do with the request factory servlet jar. Do you need a new artifact, e.g. requstet-factory-servlet-jakarta.jar?

niloc132 commented 1 year ago

Thanks! I'll reply to those PRs separately to discuss there.

For requestfactory-server.jar, yes, I think we would like a requestfactory-server-jakarta.jar, so that requestfactory users who would like to update to jakarta can do it in the same way.

dbbernstein commented 1 year ago

First, a big thank you to all the folks who've been moving this along.

In case it helps, my use case is migrating from the "Community Edition" of Payara 5 (Java/Jakarta EE 8) to Payara 6 (Jakarta EE 10). I was in the middle of trying to upgrade my code when I ran into this issue. Apologies in advance if these questions are answered elsewhere but I couldn't find them: Is there an anticipated release date for support of environments that have dropped the old javax.* APIs in favor of the jakarta package? Should this upgrade work with both Jakarta EE 9 and 10? Is there any testing with JDK 17?

niloc132 commented 1 year ago

@dbbernstein This project moves at the pace of its contributors, and we're taking this issue seriously. There is ongoing discussion at https://github.com/niloc132/gwt/pull/3 on a working implementation that you can try out if you're interested.

GWT doesn't usually set dates on releases due to the nature of the volunteer work that we get. If you need a specific deadline, I encourage helping out directly, building your own fork of GWT, or helping out to fund GWT directly through open collective or contracting with Vertispan to get some dedicated development time on this.

marco11223 commented 12 months ago

hi all, we have quite a large project we need to migrate. As I understood, I could split the web-part into gwt-client- and server-projects, and leave gwt-client on javax and on the server-part use jakarta. But we also have a shared module which uses GWT-Validation: https://www.gwtproject.org/doc/latest/DevGuideValidation.html which results in validation-annotations client-side-code and server-side-code.

Or any other ideas?

niloc132 commented 12 months ago

@marco11223 You might be interested in tracking #9844 for the javax.validation concerns, and taking a look at https://gitlab.com/ManfredTremmel/gwt-bean-validators for its support for client-side jakarta validation support. You should be able then to update your client and shared code to use the jakarta validation packages.

The only limitation I'm aware of this way is that RequestFactory with server side validation will not work. RequestFactory itself isn't terribly popular, and even when I do see it, I have rarely seen its ConstraintViolation serialization used, so it is unlikely that you need this. If it happens that you do, let us know - we should track that in the other issue, and discuss a way to solve that.

marco11223 commented 11 months ago

@marco11223 You might be interested in tracking #9844 for the javax.validation concerns, and taking a look at https://gitlab.com/ManfredTremmel/gwt-bean-validators for its support for client-side jakarta validation support. You should be able then to update your client and shared code to use the jakarta validation packages.

The only limitation I'm aware of this way is that RequestFactory with server side validation will not work. RequestFactory itself isn't terribly popular, and even when I do see it, I have rarely seen its ConstraintViolation serialization used, so it is unlikely that you need this. If it happens that you do, let us know - we should track that in the other issue, and discuss a way to solve that.

looks promising. Thanks for the pointer.

DeltaPi-Dev commented 10 months ago

Hi all,

we did a proof of concept with a real (quite big) JEE8 / gwt 2.10 based application. We use GWT RPC. Due to the massive impact of moving from JEE8 to JEE10 (lots of other framework updates required!) we had to limit the test to just parts of the overall application to get some results in a meaningful timeframe.

Our test setup

Outcome

It worked for us with JEE10! Even with our non-ideal maven module setup (with mixed client/shared/server code) we were not facing any blockers.

The GWT related changes in our code were minor: adjust some imports of GWT classes, fix the javax imports and minor adjustments to the new servlet 6 API. That depends on the application, of course.

A big thank you goes to everyone involved in this GWT upgrade! It gives us the confidence to move on and migrate the whole application to JEE10.