I think that creating UIs in Java is only doable (well) when you have appropriate design tools - so in theory even Swing or OpenJFX (https://openjfx.io/) are okay.

But once you start creating web apps, it all kind of breaks down.

I'd say that Vaadin was one of the less painful attempts at getting that architecture to work: it was only hard to customize when you tried doing something lower level, especially table display with custom row/column groups and how components look, as well as only had weird issues with reloading data often, like a progress bar during long processes and only certain parts of it broke when attempting version upgrades and it only was kind of slow when you needed to recompile the widget set and it only seemed to have some non-critical resource issues in some environments and it only sometimes failed in weird ways on the server.

Contrast that to PrimeFaces (which is based on JSF), the bane of my existence in legacy projects: complicated life cycle that generally causes bugs with dynamic pages and complex use cases, dynamic component ID generation but querying that only works sometimes properly (the whole naming container distinction), the need to bind front end state to back end fields, but also needing to expect lots of getter/setter calls, especially when you also need to throw in serialization for objects that you'd like to connect to your dropdowns, which in practice will more often look like storing the IDs from another list of options (though even simple things can break, like your dialogs disappearing after AJAX if someone didn't bind the visibility parameter), just generally a hard time creating custom components with their own back end behavior, especially when trying to reuse those in different contexts, problems if you ever need to mix JSF and JSP tags and even libraries like OmniFaces breaking on you, especially after updates. Honestly, I'm afraid that I don't recall most of the particular details, but on a 5-10 year old project my experience with PrimeFaces could be summed up with one word: pain.

I'm not saying that you absolutely cannot write good applications with a server side rendered approach, even with the more complex state management solutions (e.g. what Vaadin or PrimeFaces/JSF have), it's just that in practice you might be biting off more than you can chew - because once you venture off the beaten path, you'll find that the abstractions will leak their details and you'll be dealing with things that would have been easy with JS/TS/CSS/HTML becoming hard.

That said, Angular also feels a bit more complicated than it needs to be (though it does have a nice amount of functionality out of the box), personally I'd look more in the direction of React, or more recently, Vue (since it seems to do hooks a bit better than React), with simple RESTful API in the middle. That way, you have a clear separation between the front end and the back end, both remain testable and debuggable in separation, there's no leaky abstractions to deal with (or at least the ones that are there are mostly well known and you also won't kill your career by becoming a developer of a largely obsolete tech either).

Even with all of that, I might still look in the direction of Ruby on Rails, PHP with Laravel or even Java with Vaadin for when I need an admin panel and there are few design requirements to speak of - only functional ones for the most part.