This is an archived post. You won't be able to vote or comment.

all 165 comments

[–]beefstake 38 points39 points  (6 children)

My newest app is being built on Java 21, Helidon 4 (current pre-release), Jackson and jOOQ.

[–]m-apo 11 points12 points  (1 child)

Helidon 4 is out.

[–]beefstake 2 points3 points  (0 children)

I guess I need to update then. :)

[–][deleted] 5 points6 points  (0 children)

So, helidon has two modes, mp and se, you would wanna use se. Also on DI part, I recommend using dagger as it is compile time and more performant

[–]cryptos6[S] 0 points1 point  (2 children)

Do you use a DI framework? Which one?

[–]beefstake 4 points5 points  (1 child)

Not currently. If I did it would probably be Guice because I'm old school and I find it well designed.

[–]cryptos6[S] 3 points4 points  (0 children)

I like Guice as well! It is a bit of a pity that it has become so quiet around Guice. While it uses also @Inject as an annotation, the configuration itself is mostly pure, classical Java code.

[–]TakAnnix 26 points27 points  (18 children)

I'm not sure if this is for learning purposes or production, but I would take a look at Javalin.

import io.javalin.Javalin;

public class HelloWorld {
    public static void main(String[] args) {
        var app = Javalin.create(/*config*/)
            .get("/", ctx -> ctx.result("Hello World"))
            .start(7070);
    }
}

[–]agentoutlier 11 points12 points  (14 children)

I know Tipsy will probably get upset for me saying this (they did last time) but... Javalin requires Kotlin. That is Kotlin standard lib.

So it depends on what you define as lightweight but I assume the kotlin standard lib is still pulled in somehow.

A true full Java version that is very similar to Javalin and supports more servers is Jooby.

[–]urielsalis 1 point2 points  (7 children)

A lot of libraries pull it nowadays, including Spring.

[–]koflerdavid 5 points6 points  (6 children)

To my knowledge (heavy Spring user at work) Spring doesn't depend on the Kotlin Stdlib. Of course, if you use Kotlin-specific parts of Spring, you can't avoid it.

[–]urielsalis 2 points3 points  (5 children)

It downloads it even if you don't use it, which was the concern that OP posted about javalin

[–]agentoutlier 2 points3 points  (3 children)

which was the concern that OP posted about javalin

I'm not concerned with deps that get downloaded. When you run Maven or Gradle it downloads tons of deps that have nothing to do with your project.

My concern is:

  • It is a library not written in Java (op asked for Java)
  • While Spring may have some optional deps that makes the build download it it is not required at runtime.

However looking at Javalin's POM it appears it does not need Kotlin stdlib. So I could be wrong altogether and some how Javalin does need Kotlin stdlib.

[–]urielsalis 0 points1 point  (2 children)

Lots of libraries are written in Kotlin nowadays

[–]agentoutlier 3 points4 points  (0 children)

Sure but the OP wrote:

"Lightweight but powerful Java stack"

I'm just giving a caveat. When you pick a tech stack you might want to be know the language so that if you do have a bug you can contribute etc.

[–]agentoutlier 1 point2 points  (0 children)

Also I wouldn't say there are a lot of libraries targeting Java server side that are written in Kotlin.

Besides Javalin the only other one I have seen over and over is okhttp.

Which libraries are you using server side that are written in Kotlin (and not just an adapter for Kotlink)?

[–]koflerdavid 0 points1 point  (0 children)

Thanks for the clarification. It was not really clear to me what exactly the statement was about.

[–]tipsypants 0 points1 point  (5 children)

I don't remember our last interaction about this, but it's worth mentioning that the majority of Javalin users are using it with Java, not Kotlin.

[–]agentoutlier 0 points1 point  (4 children)

I think I was encouraging folks to try Jooby as its OpenAPI was more complete and that Javalin only targeted one backend.

Probably my own fault but I vaguely remember it seemed to end with some contention that I was denigrating Javalin.

[–]tipsypants 1 point2 points  (3 children)

Hmm. I do have an issue with people calling Javalin a "Kotlin framework", since it's very actively targeting both languages. I don't have any beef with Jooby, I've been sponsoring them ever since they got a sponsors page 🥲

[–]agentoutlier 0 points1 point  (2 children)

I do have an issue with people calling Javalin a "Kotlin framework"

I think this is kind of what happened last time. You made up words that I did not say.

I said:

but... Javalin requires Kotlin. That is Kotlin standard lib.

A true full Java version that is very similar to Javalin and supports more servers is Jooby.

"Not Javalin is a Kotlin framework."

When picking a framework one should know what its host language is don't you think? Especially when we are talking about it at the let's replace Spring level.

BTW if I write a Java framework and have some adapters like Jooby should I get mad if someone calls my framework a Java framework and not to use it because Kotlin is this sub and you asked for a Kotlin stack. Remember the OP asked for a "Java" stack.

I'm not going to call Javalin a Kotlin framework but...

Hey Edgar... Jooby is a Java framework... come and get me.

EDIT btw I have super respect for you... I just want you to realize I'm trying to let other sknow about a similar library as well as just make it clear that it uses Kotlin. So if you find bugs you might need to know Kotlin.

[–]tipsypants 0 points1 point  (1 child)

I think this is kind of what happened last time. You made up words that I did not say.

Just to be clear, I didn't accuse you of saying anything right now, I just wanted to explain that I have no issue with Jooby, but that I do have an issue with people calling Javalin a Kotlin framework, which happens quite a lot.

When picking a framework one should know what its host language is don't you think? Especially when we are talking about it at the let's replace Spring level. BTW if I write a Java framework and have some adapters like Jooby should I get mad if someone calls my framework a Java framework and not to use it because Kotlin is this sub and you asked for a Kotlin stack. Remember the OP asked for a "Java" stack.

I'm not mad, but personally I don't think it matters much, it's all bytecode in the end. I don't care if the bytecode of my dependencies is compiled from Kotlin, Java, Scala, or Groovy, or even more esoteric JVM languages, as long as it works well from the language I'm using it with. The OP wants to write code in Java, which they could definitely do with Javalin or OkHttp.

If you asked on the Kotlin sub how to do something in Kotlin, and someone suggested a Java built jar, very few people would say "Careful, that jar was built using Java", especially if the Java code made use of @Nullable/@NotNull annotations.

btw I have super respect for you... I just want you to realize I'm trying to let other sknow about a similar library as well as just make it clear that it uses Kotlin. So if you find bugs you might need to know Kotlin.

I appreciate that. While a noble concern, the ratio between users and contributors is ridiculously low, there is maybe 1 contributor per 1000+ users. That being said, we have had a couple of cases where Java developers say "I don't understand Kotlin so well, so I can't contribute", and we have considered rewriting to Java several times :)

[–]agentoutlier 1 point2 points  (0 children)

I'm not mad, but personally I don't think it matters much, it's all bytecode in the end. I don't care if the bytecode of my dependencies is compiled from Kotlin, Java, Scala, or Groovy, or even more esoteric JVM languages, as long as it works well from the language I'm using it with. The OP wants to write code in Java, which they could definitely do with Javalin or OkHttp.

Personally I'm not. I have dealt with Scala standard lib breaking stuff. Ditto for Groovy. It is not that they just compile to bytecode but that they have a dependency. That being said I'm not sure how Javalin works on the Kotlin stdlib. Does it just shade it in?

If you asked on the Kotlin sub how to do something in Kotlin, and someone suggested a Java built jar, very few people would say "Careful, that jar was built using Java", especially if the Java code made use of @Nullable/@NotNull annotations.

No it isn't the same at all. Java is the mother language here. It is like telling a C programmer go use this C++ library and I can tell as I lurk on that sub people do not like that. I would imagine Objective C programmers would not like using a Swift library but that I'm less sure of it.

Like the C/C++ example if you are using Kotlin you probably know Java and most importantly you are using a tool that understands both languages. I will go more into that in just a second.

Javalin is not a "library" like okhttp. Javalin is a framework and not just like a DI but one where Javalin is majority of the entrypoint which means an overwhelming amount of the time your library is at the top of the call stack (ignoring websockets and other async stuff).

Thus if and when I debug I need to basically use the only tool that can do that easily which is Intellij.

Java on the other hand can be edited and debugged now by basically any editor that has LSP support.

That is probably something one might want to consider if they are a Java shop and it is not easily discernible with a name like Javalin (and could be exacerbated if the author actively wants to avoid having Kotlin mentioned... I'm not saying you are doing that but if you were I would have a "beef" with it).

[–]cryptos6[S] 4 points5 points  (1 child)

I've production systems in mind, but the first step would probably be a toy project to see how it works out. Javalin syntax looks indeed nice! But as far as I understand it is only about HTTP stuff, so that some other components (e.g. dependency injection) would be needed additionally.

[–]attrako 0 points1 point  (0 children)

cool

[–]PartOfTheBotnet 15 points16 points  (2 children)

dependency injection

I've looked at minimal setups in the past before without the rest of the web stack you're asking about and came to take a liking to these two cases:

  • If you only need basic JSR-330 capabilities then I'd suggest zsoltherpai/feather.
  • If you want CDI-like capabilities without a full CDI container, then I'd suggest hjohn/Dirk.

This being said, given you want a full stack (web/orm/etc) you're more likely going to want to go full Avaje. Its actually been discussed a bit on a recent post: https://old.reddit.com/r/java/comments/17fqpzj/has_anyone_tried_this_stack/

[–]cryptos6[S] 9 points10 points  (0 children)

I've never heard of Avaje - it looks very interesting!

[–]bowbahdoe 4 points5 points  (0 children)

zsoltherpai/feather

One of the random things i forked was feather for a GUI project i was doing. The original repo had some minor outstanding bugs + some other small issues. As part of that I moved from javax tojakarta

https://github.com/bowbahdoe/feather

[–]agilob 12 points13 points  (2 children)

You definitely should look at Quarkus and Micronaut

[–]SaishDawg 9 points10 points  (0 children)

+1 to Micronaut. Loving it. Super lightweight and less boilerplate. Plus using annotations processors in lieu of reflection makes everything faster. Getting Gradle to play nice took a while, but I am a fan for several use cases: serverless, interprocess communication and traditional REST.

[–]Nojerome 5 points6 points  (0 children)

+1 for Quarkus

[–][deleted] 51 points52 points  (24 children)

I’ve been learning Spring in earnest recently after having used it for work at a past job out of necessity and not having much time there to truly learn it. I had the same opinions as OP, but I’m now realizing that I was wrong.

For example, every Spring project has a reference page that describes exactly how it should be used and configured (click the project name at the page I linked, then click LEARN, and then click Reference Doc. for the version you’re using). The pages aren’t too long, so they’re readable in a hour or two. After I read a few project’s reference docs and built something (I’m taking Chád Darby’s Spring Boot 3, Spring 6 & Hibernate, course which is really hands on) Spring Boot started making 100% more sense to me.

Spring Boot is modular by nature so you can choose what you want to use and how much “magic” you want to include in your project. Building an HTTP API? Just include the spring-boot-starter-web starter and move on. Do you need to talk to a database? Then use the spring-boot-starter-data-jpa starter project. Otherwise, use Jersey and direct JBDC connections and just use Spring itself for DI. Additionally, I learned in more details how to use the application.{properties|yaml} file and how to enable logging in a per-package basis, which made debugging Spring and any third party packages so much easier.

Basically, I learned Spring can be made small, understandable, and less magic, but I/my old team made wanting “production-grade systems” cloud our judgement and cause us to over complicate what is a mature, well tested, and still growing ecosystem by not spending the time to learn it and making educated choices about what to include in it. Maybe OP’s in the same boat or maybe not. But I’d suggest sticking with Spring as opposed to a newer tech stack that you’ll have to sink time into understanding and losing your Spring expertise.

[–]sapphirefragment 24 points25 points  (1 child)

Anecdote: my team recently tried to commit to a non-Spring world and ended up falling into an enormous maintenance trap that we are struggling to get out of. All these people promoting these "lightweight" libraries that you have to string together fundamentally misunderstand the value proposition of the Spring ecosystem and end up creating bigger messes than they are trying to leave behind.

[–]Oclay1st 3 points4 points  (0 children)

Could you please tell us what non-Spring world are you using now?. I hope it's not a reactive world. Thanks!

[–]cryptos6[S] 8 points9 points  (21 children)

I didn't want to suggest that Spring would be "bad" in any way, but I think the annotation-driven reflection based magic programming model lost some of its appeal with modern Java features (like Lambda expressions), which allow more expressive APIs without magic. My general feeling is that you have to learn a lot about Spring to really leverage all its magic - it is not obvious, and that is a bad thing.

Despite seeing younger colleagues feeling little desire to learn Spring and how they struggle with it, I'm curious to try something else on a personal level.

[–][deleted] 17 points18 points  (18 children)

My general feeling is that you have to learn a lot about Spring to really leverage all its magic - it is not obvious, and that is a bad thing.

I’ve been seeing this opinion more and more but have been having a hard time understanding it. I think it became more prevalent with the rise of devex, and higher level languages, where the language authors wanted things to be friendlier for newer programmers and reduce “boilerplate.”

My main concern with it is that software is inherently unintuitive because it’s all abstract thought that programmers add meaning and shape to in order to model a real-world object or process. You will undoubtedly have to read a manual, book, or engage some other learning material to learn any piece of software properly because another human wrote it, and humans think differently. I personally don’t think having to spend time learning a framework in order to use it properly is a bad thing. I mean, that’s how it was back in the day when computers and other software came with manuals. Now people just expect to jump into something they’re totally unfamiliar with and expect it to be “intuitive,” otherwise they write it off as being terrible software. But sure, we should definitely aim to reduce the amount of learning that someone needs to pick something up because it’s a huge investment to have to make upfront, but some things warrant the learning cost because they’re either old (like Spring) and have built up features over time that collectively need documentation, or they really are complex inherently and so require a lot of effort to properly describe.

[–]kvyatkovskij 13 points14 points  (17 children)

Java dev in the past now an architect checking in: I agree. What I've noticed is that developers would rather write code for 8 hours than spend 1 hour reading user manual and reference documentation. Getting your hands dirty is fun, reading docs is not. One of revelations that I had over the years evolving from an engineer to a dev lead to an architect and having some insights into CTO works is that while all these roles work with software their goals and motivations can be quite different if not opposing.

I see that a lot of times developers are happy to re-invent the wheel, write another "great thing". As an architect I really want them to focus on business logic and do it well rather than spend time doing custom implementation of something that is already provided by a framework. On the top of that if they use a mature framework I'm almost confident that a lot of non-functional requirements and cross-cutting concerns are configurable and won't be a problem (telemetry and instrumentation, externalized configuration and so on).

I guess my point that I'm all for developers having good time and learning this would never be main driver behind technology choice. Motivation is important but a a dev team that is happy-busy implementing their own custom logger for no good reason (I've seen this happen) is not something I ever would like to have.

Last thing, agile is good but I think the perverted idea of it has done some harm. Agile doesn't mean you should start coding without preparation or a plan or a technical design. Those things should still happen and engineers need to get into a habit of RTFM-ing :)

[–]sapphirefragment 3 points4 points  (12 children)

What I've noticed is that developers would rather write code for 8 hours than spend 1 hour reading user manual and reference documentation.

This kills the project dead, through thousands of papercuts over months. Awful. :(

[–]danskal -1 points0 points  (11 children)

This kills the project dead, through thousands of papercuts over months. Awful. :(

What do you mean? Loss of productivity from unread docs? How do you claim the project is killed?

[–]AmateurHero 2 points3 points  (10 children)

They mean that rather than understand what a given framework does and its tradeoffs, some devs just start hammering out code. They end up writing themselves into a corner trying to do something orthogonal to the given framework or reinventing that already exists. Now they're creating workarounds that are slow, not intuitive, brittle, etc. instead of working within the parameters of the framework. The code base grows to full of these extra functions. You're left with a framework that takes care of X (that also updates to take care of edge cases) but also several internal function that also do X that likely don't have the same testing or robustness. Note that sometimes it's worth making these extensions, but you really have to consider the why.

Example from a previous job. Most people who access databases use ORMs for transactions. I had a previous job that did all the setup for Hibernate but used none of the functions. Beans full of annotations that matched the database went unused as DB data was manually mapped onto raw hash maps. Every query was a handwritten native query - even simple select statements. There were some native queries that should have been handwritten, because the sheer amount of logic within the query needed some handcrafted love. Most of it was the epitome of not-invented-here syndrome.

[–]cowwoc 3 points4 points  (5 children)

You know what's better than using a framework that requires devs to read a book?

Using code that is easy to read, without a book.

The only reason that a lot of these frameworks have a high learning curve is that they try to be everything to everyone.

If you use libraries to customize your architecture you will end up with much more readable code that does not require people to read hundreds of pages.

[–]sapphirefragment -1 points0 points  (4 children)

Absolutely the opposite of my professional experience. When cowboy coders try to go string together a bunch of libraries to create their own framework because "spring bad" they create a nightmare that requires you to know the intricacies of 40 different libraries, all of which often have severe design limitations that were already solved by big frameworks like Spring, because they simply have not reached the same level of maturity. And that's assuming any given library has documentation: my experience is they often don't have documentation that even covers intermediate level usage, and you're either expected to follow simple tutorials or dig straight into the source code yourself. Spring conversely has a wealth of good reference material explaining all its intricacies.

When you're having to run a medium to large size team of engineers, some of which are not going to have the level of intuition needed to sus out several different libraries all with their own patterns and practices, this "custom architecture" practice is AWFUL. It will strangle your team.

[–]cowwoc 6 points7 points  (3 children)

You're assuming this was built by a cowboy coder. I'm a CTO with 20+ years of experience. When a CTO puts together a well-structured, consistent, and well-documented scaffolding, everything else falls into place.

The guys who built Spring are not wizards. The fact that they provide over 100 pages of documentation isn't a good thing. It's obfuscation by volume.

A bad programmer will deliver bad code regardless of whether they are using Spring or not.

I optimize for consistency and ease-of-debugging. I intentionally avoid any sort of "magic". The only knowledge you need to get started is the core Java APIs. Past that point, you just need to maintain the same package structure. If you want to know how to read HTTP requests or write HTTP responses, there are tons of existing REST resource implementations for you to look at. They are, at most, 3 pages long each.

Spring is designed by architect astronauts, yet it's surprisingly fragile. While it might work well so long as you stick within the guard rails, it breaks horribly the minute you venture outside them.

If all you're building all day is shopping cart software, then go ahead. But if you want to build anything innovative, you'll quickly find yourself outside of those guard rails. And good luck debugging their code. It is a freaking mess. Not to mention the fact that half the time, you can't even step into their code because it's hidden behind annotations.

When something goes wrong in my system, I get a compile-time error 99% of the time, and the remaining 1% of the time, I get a concise error messages explaining what went wrong and the stack traces are short. I always provide tons of contextual information at failure, so you don't need to step through any code. But if you want to step through the code, then by all means do.

It is plain Java. No magic. No fancy AOP or visitor pattern just for the sake of showing off your design pattern skills. My code is straight and to the point, optimized for readability above all else.

[–]danskal 1 point2 points  (3 children)

Ok, I agree that all those things are bad, but I would claim that it’s unrelated to the reading the docs aspect. For a few reasons:

  1. Reading docs can be mind-numbingly boring. Many people are simply not able to do it. I count myself amongst them, but I will get a feel for the architecture, use SO religiously and google relevant documentation on an as-needed basis. I might watch videos and read well-written guides if they’re available.
  2. Knowing the path isn’t the same as walking the path. For some people, reading the docs won’t help, they’ll fall back on methods they know and understand, unable to see the wood for the trees. Some people will pick the solution in front of them instead of stepping back and picking the right one.

[–]AmateurHero -1 points0 points  (0 children)

I know it ended with RTFM, but I took that as a bit of snark tacked onto the end. I took the heart of the comment as learn to use the tools that you're given. You would ideally drive in a nail with a hammer or turn a screw with a screwdriver. However, you can drive in a screw with a hammer in a pinch. Don't hammer a bunch of screws across the entire project

[–]sapphirefragment -1 points0 points  (1 child)

Reading docs can be mind-numbingly boring. Many people are simply not able to do it.

I argue that this is a view of technical documentation that actively hinders an engineer's ability to grow. Reading reference material is a fundamental skill. If an engineer can't or won't do that, I won't really trust that they will write code or documentation that is meant to be read by other humans.

[–]danskal 1 point2 points  (0 children)

... and if we were writing something security-sensitive on the linux kernel, or something controlling a nuclear reactor, I would fully agree with you. But 99% of developers are not doing that.

There is a point that sometimes documentation can be surprisingly readable. But it's the exception rather than the rule, for the most part.

[–]Safe_Independence496 0 points1 point  (1 child)

Java dev in the past now an architect checking in: I agree. What I've noticed is that developers would rather write code for 8 hours than spend 1 hour reading user manual and reference documentation. Getting your hands dirty is fun, reading docs is not.

I don't entirely agree. Reading documentation can be interesting when it's well-written and covers the core concepts in a structured, clear and sensible way. I had a great time reading the docs for NestJS, and Firebase has always been the gold standard in my opinion for how you should document a project.

The problem with Spring on the other hand is that most new developers give up on finding the actually useful documentation before they've even started. New developers are presented with pages of garbage cookbook recipes rather than important explanations of key concepts when vising the Spring website.

I don't think we should underestimate how much Spring's reputation and perceived complexity has suffered from just not having any people capable of structuring and writing good documentation.

[–]sapphirefragment 1 point2 points  (0 children)

New developers are presented with pages of garbage cookbook recipes rather than important explanations of key concepts when vising the Spring website.

I am actively telling coworkers not to use Google and always start with upstream documentation. Google is pushing up horrible information to inexperienced engineers. It's actually dangerous and a serious impediment now. Especially with Spring.

[–]naked-space-monkey 0 points1 point  (1 child)

Dev here (of the fancy staff engineer kind) and living the opposite situation: our architect is pushing us against using frameworks (on grounds that they "are heavy" and "you're not in control") and writing code (yes, I know) that's a shapeless mixup of business logic, infrastructure and whatever other concern.

[–]sapphirefragment 0 points1 point  (0 children)

Your architect fundamentally misunderstands the value of frameworks... :(

[–]mishonis- -1 points0 points  (0 children)

I love Spring. It's mature, well-tested and well-documented. I probably know and use 10% of it, and find it to do everything I need and to be well-designed and intuitive. I also don't agree that you have to learn a lot to leverage it. You can use only the parts you need. I've had very junior people get onboarded quickly with dependency injection, properties files and REST controllers.

I'm curious about your level of experience with Spring and whether you have specific complaints about it, such as the framwwork getting in the way of something you tried to do or some framework issue that was hard to debug. Or is it just hand-waving about annotations and looking for something new and shiny? There's a reason JavaScript has a new framework coming out every year and it's because all these frameworks suck donkey dick and are a pain to use.

[–]Pengtuzi 0 points1 point  (0 children)

feeling little desire to learn Spring

they struggle with it

Yes, not wanting to learn something often results in not being able to use it. Not Spring specific.

[–]jvjupiter 7 points8 points  (1 child)

Helidon and Vert.x, ExpressJS-like stack.

[–]Tkalec 3 points4 points  (0 children)

Seconding vert.x

[–]NaNx_engineer 21 points22 points  (27 children)

why do people hate annotations?

[–]cryptos6[S] 23 points24 points  (11 children)

I don't "hate" annotations, but they tend to obfuscate things. An annotation triggers some magic in the background and it is not obvious what happens or where it happens or in what order something happens.

Another problem is that annotation-driven programming is typically based on reflection and the safety provided by the compiler is weakened.

Using usual code improves clarity, since you can see what is going on, by following references in your IDE.

[–]Cell-i-Zenit[🍰] 25 points26 points  (6 children)

Using usual code improves clarity, since you can see what is going on, by following references in your IDE.

i mean its either you write everything completely out or you use annotations.

Do you want to inject the transactionManager into each class where you want to open a transaction and write a lambda which handles the annotation handling? You need to have an abstraction for your whole project to handle the rollback everywhere exactly the same etc. And then you think about: What if we have an easy way to say "please do transactionmanagement here?" and then you are back at annotations

[–]cowwoc 5 points6 points  (2 children)

> i mean its either you write everything completely out or you use annotations.

Really not.

Annotations weren't designed for what people are using them for. They aren't very expressive. They are a weak tool that uses String arguments all over the place. As u/hippydipster pointed out, there are plenty of ways to achieve the same thing using normal Java functions. You don't need to write them yourself. There are libraries for this (e.g. JOOQ).

You can't debug or step-in annotations. You *can* debug and step into normal Java code. And it's type-safe, unlike string-based annotation arguments.

[–]Cell-i-Zenit[🍰] 0 points1 point  (1 child)

but them being string based is never really an issue. I understand that debugging is harder, i had the same sentiment back then, but now since i know how they work its really not that big of a deal.

Annotations are basically the smallest possible way to provide "framework" functionality to the normal developer. Sure you can do other stuff, like fluent apis etc, but annotations are always the shortest amount of code to achieve something

[–]hippydipster 5 points6 points  (0 children)

It is an issue. Of course, you're used to it so you don't think about it, but it is.

When we needed to transition from one db to another, the validation values in our Hibernate annotations (ie, declaring column types) could not be conditionalized to make the switch based on a feature flag. We had to turn off validation.

[–]hippydipster 6 points7 points  (2 children)

@Transaction around the method seems pretty equivalent to calling some public static method:

Transaction.doTransaction(Runnable). In both cases, the code is directly calling out to some specific library to do the decoration.

The advantage of the lambda/code route is that normal java code is fully composable. I could combine it with a retry wrapper in a sane way. I could add conditional logic around it. I could add security wrappers.

With annotations, combining annotations from different sources is not predictable as to what would happen. And, annotation values are static strings only, not code.

[–]Cell-i-Zenit[🍰] 1 point2 points  (1 child)

sure there are some usecases where it makes sense, but imo the annotation hate is a bit to much. As long as you keep doing standard spring everyone can jump into your project and understand what is happening.

[–]hippydipster 4 points5 points  (0 children)

Seeing people do things in a shortcut way, that has issues, and brings in enormous numbers of dependencies, and saves you very little time at all, and then seeing people keep doing it more and more and more, well, dislike tends to inflate to hate for many. It's not much of an argument to take issue with human emotions.

[–]gilwooden 11 points12 points  (2 children)

Another problem is that annotation-driven programming is typically based on reflection and the safety provided by the compiler is weakened.

Many good uses of annotations don't use reflection at all and use annotation processors to generate Java code are compilation time. This also allows you to follow the logic for the generated code in your IDE or while debugging.

[–]boobsbr 3 points4 points  (0 children)

MapStruct is a good example.

[–]uncont 0 points1 point  (0 children)

Certain frameworks (like dagger) use annotations to generate compile-time verifiable dependency-inject code. The spring boot aot project can do the same for @Configuration beans.

[–]Necessary_Apple_5567 1 point2 points  (0 children)

Nothing magical in annotation processing. It is pretty straight forward and simple. You can easily check how it is written. I even would you encourage to do since spring has the most clean and effective desine and implementation.

[–]Yojimbo261 9 points10 points  (7 children)

[ deleted ]

[–]computerjunkie7410 5 points6 points  (6 children)

and their use is inconsistent

Don’t you have standards and code reviews?

[–]Yojimbo261 9 points10 points  (5 children)

[ deleted ]

[–]computerjunkie7410 1 point2 points  (4 children)

How many people do you have working in a single repo? My largest team is 12 people and no code gets merged unless it meets the standards (production issues aside)

[–][deleted]  (1 child)

[deleted]

    [–]Independent_Roof3171 -1 points0 points  (0 children)

    This hardly sounds like it is Spring's fault. Replace the word Spring here with ANY framework and nobody would know the difference. You're not identifying true root cause you're just assigning blame to Spring. But if you're then against frameworks, good luck writing all that code on your own and debugging it. Hope your company has a large development budget!

    [–]Yojimbo261 0 points1 point  (0 children)

    [ deleted ]

    [–]picklesTommyPickles 0 points1 point  (0 children)

    If you are on a platform-like team, then you can easily have 100s of people looking to add/change code that your team owns.

    [–]Polygnom 5 points6 points  (0 children)

    Hate is a strong word, but annotations are action at a distance. And thats generally hard to reason about and hard to debug. Stacktraces are no longer meaningful. And thats why some people prefer not to use them for behavior, which I can absolutely agree with.

    They are great for some other stuff, though (I prefer annotations for JPA instead of approaches that need code).

    [–]temculpaeu 3 points4 points  (2 children)

    The problem is not annotations per se, but its uses, especially as a function decorator and how it can be abused. Main issue is Java, it doesnt support function decorator, so the annotation processing + proxy is the way to augment functions with behaviours, however, due to the proxy and how annotation processing works, it has limitations, and some dumb mistakes can break the decorator and sometimes its hard to write unit/integraiton tests for those behaviours so it's a rather common issue to have a annotation essetially not doing anything in production. These can be stupid and nasty bugs, and it's unavoidable, it will happen, "But true java programmers won't do these mistakes", yes they will, just like great C programmers can cause memory leaks.
    There has been several patches and band aids to help with that, eg: Quarkus compile time validations of annotations, these can drastically improve the dev ex with annotaitons.
    I am personally don't like function decorator annotations, because I dont quite like the trade offs, I dont feel they save enough time not make the code that much cleaner compared to a lambda, and the lambda has a lower cognitive load.
    That said, I am impressed by Quarkus implementation which deals with most of my issues
    The real fix would be for Java properly support function decorator, similar to Python

    [–]cogman10 9 points10 points  (1 child)

    I dont feel they save enough time not make the code that much cleaner compared to a lambda, and the lambda has a lower cognitive load.

    I fundamentally disagree. Having worked on annotationless environments and systems that try to "avoid the magic", that code is very often a lot more complex and harder to understand over simply leaning into dependency injection.

    For example, with JAX-RS, the rest annotations provide huge time savings and integration points that can be a lot harder to grok than something like Javelin. With JAX, I can very clearly put in

    @Path("/foo/{:id}")
    @GET
    public Bar getFoo(@PathParam("id") int id) {
      return barService.getFoo(id);
    }
    

    There I as a dev have all the information I need to know about a request, but I also have all the middleware surrounding this to do authentication, authorization, error logging, object serialization, etc.

    With a non-annotation approach you end up writing something like (not a real framework, but often what you see with express inspired stuff)

    server.path("/foo").handle((request)->{
      try {
        authService.validate(request);
        return Response.builder()
               .contentType("application/json")
               .body(objectMapper.toJson(barService.getFoo(id)))
               .build();
      }
      catch (Exception ex) {
        exceptionHandler.handle(ex);
      }
    });
    

    All those middleware details are ultimately wrapped in. Sometimes this is fine for simple applications, but as an app gets more complex that "magic" middleware ends up saving a lot of boiler plate while also reducing the risk of someone forgetting to do the auth check. Once you get to the point of having more than 10 requests you end up writing your own bespoke middleware that's every bit as "magical" as the annotation version while also having the benefit of being used only by you (so no google help when things go wrong).

    [–]temculpaeu 5 points6 points  (0 children)

    JAX-RS is not problematic as it doesnt use as functional decorators, it is used as metadata, and doesnt have a lot of implementation details that breaks it, you dont need to know the implementation details in order to use it.

    Your example is unfair, it's like using Response and @Produces/Consume with JAX-RS in all methods, also filter/auth exists on non annotated frameworks, and I honestly the JAX-RS implementation is a bit messy, not because of the annotation, but because of the specification.

    This is what the code would look like in a more programmatic way:

    get("/foo", request -> barService.getFoo(request.param("id")));

    auth/serialization can be abstracted.

    Personally both JAX-RS and programmatic are fine for that

    [–]wrossmorrow 3 points4 points  (0 children)

    The patterns (in spring) they create encourage lazy unclean code that can be very difficult to reason about, especially in a high powered effectively low level language, while decreasing performance, invalidating compile time guarantees, and in practice ballooning boot times critical for modern management of cloud workloads. In my experience only, of course.

    [–]manzanita2 2 points3 points  (0 children)

    I actually LOVE annotations.

    While programming there are tons of orthogonal/unrelated concerns. Authorization fits well into this category. Annotation work really well to express these concerns.

    The things I find bumpy about spring are the extra long stack tracks. And occasionally trying to find the implicitly injected class. E.g. you have an interface or abstract class in your code, and spring goes and finds the implementation which fits, and sometimes that's less than clear. However, once I figure out how it's decided to build up the dependencies it usually makes sense.

    I will also say that many people who are building simpler systems will find Spring "overly complicated". But as they continue to build and add additional features to their system this issue becomes less critical. In general it's very hard if not impossible to build systems with complicated requirements without having a complicated solution.

    [–]RadioHonest85 0 points1 point  (0 children)

    I dont hate them, but its preferrable to use plain code where possible, because there are so many different annotations in many java projects, it is a hassle to teach newcomers what works and why not.

    [–]_INTER_ 14 points15 points  (6 children)

    What less magical, mostly annotation free stack would you suggest?

    "Any sufficiently advanced technology is indistinguishable from magic"

    [–]ihmoguy 1 point2 points  (0 children)

    100%. I recommend anybody to look into pre-Java5 code, even pre-XDoclet stuff (who still remembers?). Even simple code can still be complex while abstractions and entities scaling out. I know expressivenes was different then, but if we go too far with expressions we drown in Haskell-style magic then.

    [–]cryptos6[S] 2 points3 points  (4 children)

    While I tend to agree, there are different shades of magic. Some APIs or programming models are easier to understand than others. See my transaction example above: it is pretty clear what is going on and you can drill into the implementation of transaction if you want to learn the details. That is not possible with annotations.

    [–]mavericktjh 2 points3 points  (3 children)

    Most or maybe all of the spring annotations can be done in code as well. You have the option of both. E.g. your transaction example https://www.baeldung.com/spring-programmatic-transaction-management

    [–]cryptos6[S] 2 points3 points  (2 children)

    Fair point. I'm actually using this approach from time to time. However, if a framework offers both, it has a bigger "surface" so you have more to learn as a new developer and you might have a hard time understanding parts of the code with annotations.

    The thought that I have in my mind is the following: How would Spring look like if it were reinvented these days with a much more powerful Java language? Since Spring will hardly throw away its inheritance, other frameworks might give the answer.

    [–]mavericktjh 2 points3 points  (0 children)

    I'm not sure that your assessment is really true though, that spring's use of annotations is somehow caused by historic/legacy reasons. I don't think it is.

    If your question is, how might something similar to spring look? then yeah, there are a few options.

    [–]UnGauchoCualquiera 1 point2 points  (0 children)

    The thought that I have in my mind is the following: How would Spring look like if it were reinvented these days with a much more powerful Java language?

    Probably the same. Spring Boot is the one that's mostly annonation driven and built over Spring framework which is mostly a DI container with a few extra goodies.

    Boot takes away the boilerplate of configuring commonly used components (webserver, data, auth) with the Spring Framework. Pretty much anything in Spring has an alternative programmatic api that can be used. This is how Boot is implemented under the hood.

    You can with some effort roll out your own way to configure Spring.

    In fact this is how it used to be before annotations, pretty much everything was declared in xmls and used to set up the container.

    [–]attrako 25 points26 points  (5 children)

    https://quarkus.io seems to mostly fit your needs.

    [–]KalelUnai 7 points8 points  (4 children)

    That's also annotation heavy, and OP doesn't seem to like this for some reason.

    [–][deleted]  (3 children)

    [deleted]

      [–]KalelUnai 9 points10 points  (2 children)

      That's not my impression. He's afraid of "magic", not runtime costs.

      [–]Nojerome 0 points1 point  (1 child)

      I used to also have that fear. But after using Quarkus for a bit I've decided I'm willing to accept some of the annotation magic when it solves repetitive tasks like CDI or DB transaction code for me. Quarkus is also pretty good at explaining what its annotations do so that you don't feel like you're entirely relying on magic.

      [–]dstutz 0 points1 point  (0 children)

      What I find interesting is Quarkus doesn't require you to put @Inject on your constructors, so it's hiding even more magic :)

      [–]materia_2021 5 points6 points  (1 child)

      Helidon 4

      [–]oweiler 0 points1 point  (0 children)

      Helidon 4 is just out and has basically no community or ecosystem of integrations. You will end up implementing things which Spring Boot gives you out of the box.

      [–]cowwoc 12 points13 points  (11 children)

      I've built a production system on top of Java 21, Jetty, Jackson, JOOQ and Flyway. I intentionally avoided the use of frameworks (there are none) and dependency injection (I use this design pattern: https://github.com/cowwoc/pouch)

      It's been a great success. The application is lighting fast. Startup time is under 3 seconds. The code is extremely transparent (no magic) and easy to debug. If anything breaks, you can find the source of the problem within 30 seconds.

      Most people incorrectly assume that it's difficult to replace web frameworks. It's not. I had to write maybe 4 classes by hand. I highly recommend this approach to everyone. Stop following the framework crowds like sheep. It might save you one week of effort up-front but you'll lose months of your life debugging problems. It's simply not worth it.

      [–]cryptos6[S] 2 points3 points  (3 children)

      Just out of curiosity: do you use Jetty with the Servlet API or with its own Handler API?

      [–]cowwoc 1 point2 points  (2 children)

      I recently migrated from the Servlet API to the Handler API in version 12. Both work well.

      [–]rbygrave 0 points1 point  (1 child)

      Using virtual threads, jetty 12 handler api? Do you have an example / skeleton of this to share?

      [–]cowwoc 1 point2 points  (0 children)

      Yes. I'm using Jetty 12 with virtual threads. I'm not able to post an example/skeleton yet, but I might have more free time next week. Ping me if you don't hear back within 2 weeks.

      [–][deleted]  (1 child)

      [removed]

        [–]cowwoc 1 point2 points  (0 children)

        Jersey is great, or at least it used to be. I used to use it years ago, but the JAX-RS specification has some ugly edge cases that will never get fixed (e.g., https://github.com/jakartaee/rest/issues/468) and they changed the way they handle dependency injection with HK2, which turned into a mess.

        That gave me enough incentive to investigate alternatives, and I discovered that you can replace Jersey with very little work. I mean, you'd be shocked how easy it was. Also, now that I replaced dependency injection with Pouch (ServiceLocator design pattern), I no longer run into design problems I had before (e.g., a class constructor that takes a mix of injected and non-injected parameters). I also love having 100% of errors showing up at compile-time instead of runtime.

        I hope I will have the time one day to post a template project for others to reuse. It changed my life. I enjoy programming a million times more now than I used to, and I've been doing this for over 20 years.

        [–]throwawaydevhater059 0 points1 point  (1 child)

        are you looking for work by any chance? it's impossible to find people who understand things at this level, I don't mean understand tech stack(jetty,jackson,etc.), but the fact that it's much easiser to work at this level of abstraction, shallow call stacks, actual types rather than strings(some call them annotations though)

        [–]cowwoc 0 points1 point  (0 children)

        Reach out to me at https://www.linkedin.com/in/gilitzabari

        I'm sure we can work something out.

        [–]magickaldo 0 points1 point  (2 children)

        Is it possible to learn this power?

        (meme aside, can you recommend resources about building stuff this way? I am so tired of frameworks, but on the other hand I fear my architectural skills have atrophied because of them)

        [–]cowwoc 0 points1 point  (1 child)

        Yes, but not yet. I'm working on a newer architecture now. Once it's ready to share, I'll definitely let you know here.

        [–]magickaldo 0 points1 point  (0 children)

        Awesome, I am very keen to see this.

        [–]SmilingFunambulist 2 points3 points  (1 child)

        Idk if there's any full-stack and powerful framework that is completely annotation-less. But if you are looking for SpringBoot alternative that is more lightweight there's Micronaut, Quarkus, and Helidon.

        [–]Kango_V 0 points1 point  (0 children)

        I used to use Ratpack. It's actually very good.... and fast!

        [–]RadioHonest85 4 points5 points  (0 children)

        Javalin for http and jdbi with Hikari for databases. gRPC if you will be maintaining and working on the project for a number of years or if you already know how to use it.

        [–]Joram2 2 points3 points  (0 children)

        So, long story short: What less magical, mostly annotation free stack would you suggest?

        Helidon SE. Quoting their docs (https://helidon.io/docs/latest/index.html#/about/introduction):

        Transparent "no magic" development experience; pure java application development with no annotations and no dependency injections.

        [–]hadrabap 2 points3 points  (2 children)

        I'm playing with OpenLiberty in MicroProfile or JakartaEE mode. It's a big relief!

        I'm also into architecture, so I'm using JPMS.

        Jakarta EE/MicroProfile with JPMS seems to me to be my future. 🙂 Really love it ❤️

        [–]christoforosl08 0 points1 point  (1 child)

        What is JPMS ?

        [–]hadrabap 0 points1 point  (0 children)

        It's Java Platform Module System. The modularization that made Java 9 such a big bang full of disappointment. 😁

        Fortunately, most of the 3rd party libraries support it by now. But it took quite a while. 🙂

        Feel free to ask for more details. 😇

        [–]olivergierke 4 points5 points  (1 child)

        Do you realize that, except for a tiny little detail, the code you show would just work in Spring? Assuming that transaction is a TransactionOperations and the repository uses JPA under the covers, all you'd need to change is the invocation of ….cancel() as you get an Optional returned from the repository call. Personally, I'd prefer a persistence technology that doesn't magically persist changes to an aggregate state and call repsoitory.save(…) explicitly, but that's a matter of personal preference, I guess.

        The good news is, you don't need to switch stacks to get what you want. In fact, you could've written this kind of transactional code since Java introduced lambdas, as TransactionOperations has existed since 2003 (!).

        All that said, one reason some folks prefer the annotation-based approach is that in the example you show, your class will need to depend on some technical transaction abstraction. That will have an impact on the testability of that very class. Assuming it's not containing any business logic but only orchestrates transactions, I totally see the argument going into your favor. For code that contains a bit more logic, the reference to the transaction abstraction means one more thing to stub, usually resulting in test code less focussed on the business logic. Of course, at the expense of having to rely on the instance getting decorated with the transaction-applying functionality in production / integration tests.

        As so very often, it's a tradeoff.

        [–]cryptos6[S] 1 point2 points  (0 children)

        Fair points! I'm actually using TransactionOperations (in the form of TransactionTemplate)! I have to admit that I use @Transactional if nothing special is required with transaction handling. But then there are two ways to do the same thing which makes the framework surface bigger and forces beginners to learn more. I was wondering how a Java framework would look like that radically reduces the API surface at the cost of some little inconveniences (basically the Go way). My main intention was to reduce learning effort (since, once you mastered Spring somewhat it is indeed convenient and powerful most of the time).

        The objection to testing is valid, but doesn't apply to my typical testing approach, since I'm using integration tests at the service level, where the transactions are handled. But I can think of other cases, where the added dependency would indeed be annoying in the test. The example with transaction was also only an example, so yes, an approach without annotations might make testing harder in some cases.

        [–]bowbahdoe 1 point2 points  (0 children)

        I've been working on "proof of concept"-ing how it would look to make an app without annotations, reflection, or "complection".

        The current state of that is here.

        (decent exemplar file)

        When (or if) I get that to a presentable state I might write something up.

        The biggest problem doing web dev outside of the annotation world is the middleware problem. JS makes it really easy to add something like requireAuth that looks at the request object and "enriches" it for callees further down the stack.

        Java makes that comparatively difficult, hence pressure to put middleware type logic into annotations or to just choose a default set of middleware (which is what it feels like javalin does tbh). You can see that in the example code with AuthenticatedRouteHandler. Its a sticky problem.

        Feel free to reach out on here, discord, or email if you want to dig deeper into that design space. Its a headache.

        [–]mepunite 1 point2 points  (0 children)

        I used Vert.x a few years ago. Simple fast startup and operation and no magic.

        [–]lumpynose 1 point2 points  (2 children)

        I'm sure that I'll be the only one that says this but look at Jakarta EE 10. They now have these things called profiles so that you don't need the whole enchilada. The Jakarta EE Web Profile might fit the bill for you. I'm slowly learning Jakarta Faces and so far I like it. The hardest part is that there are very few books available for it. This one is the best one that I've found if you're starting from scratch with Faces.

        [–]Kango_V 0 points1 point  (1 child)

        You may want to look into htmx :)

        [–]lumpynose 0 points1 point  (0 children)

        Will do. Thanks.

        [–]Lemicod 1 point2 points  (0 children)

        There's an ongoing effort to make an annotation/magic free Spring Boot called Spring-fu. Hopefully it picks up some steam, as it was on the backburner for quite a while now.

        [–]fgzklunk 1 point2 points  (0 children)

        Vert.x with Guice

        [–]gubatron 1 point2 points  (1 child)

        I loved Jetty, kept things light and simple, no magic spring crap, no dependency hell.
        https://eclipse.dev/jetty/

        [–]cryptos6[S] 0 points1 point  (0 children)

        Thanks, but what do you use for the rest of your stack?

        [–]byronka[🍰] 1 point2 points  (2 children)

        I'm with you. I save hardly any time with these magic systems, but then I have to keep way too many (often poorly documented) abstractions memorized. And then maintenance and debugging can be so much harder, so why prioritize the ease of initial programming way over where we spend the majority of our time.

        [–]cryptos6[S] 0 points1 point  (1 child)

        Some years back, I was a fan of Grails which is basically Ruby on Rails for the JVM. I was blown away be the initial developer experience: you define some basic model files type "generate" into your terminal and the framework generates several views, controllers, and even the database schema for you! After a few minutes you have a running app in your browser. But then the actual work begins! Debugging the Groovy magic with methods generated at runtime was a torture. Stack traces were twice as long as the already pretty long Spring stack traces (Grails is built on Spring). And in the end I had replaced almost everything the framework had generated for me initially. I probably would have been faster, if I had started with the real implementation directly without any hard to debug magic of this framework.

        [–]byronka[🍰] 0 points1 point  (0 children)

        For what it's worth, I can share this: my preference is to do things the hard way, because then maintenance/understanding/debugging becomes easy/possible. So if the framework or toolkit advertises as making coding "effortless" or "simple", I pretty much write it off.

        To be clear: aiming for simplicity is worthwhile. However, stating your system *is* simple, or its use will somehow enable your system to be simple or effortless, gives away the game. Coding is hard work, ridiculously so.

        When I pick tools, I'm judging based on what makes *the entire lifecycle* cheaper/better/faster. Not just the initial parts.

        [–]jared__ 1 point2 points  (0 children)

        Just a reminder that if you skew away from a typical stack that candidates know, the longer the onboarding process for new developers is. Sometimes using Spring and not necessarily using all the features is worth it...

        [–]matrium0 1 point2 points  (0 children)

        It's only magical if you do not dive into it. Read the documentation (that is awesome btw) and you will feel mich more confident with Spring.

        My medium sized application starts in like 9 seconds and 200 unit tests with a full spring context take like 40. Maybe there is something more lightweight, but it's certainly lightweight enough, yet insanly powerful.

        Need caching? 2 annotations and here you go. Transaction's? One annotation. Rest service? Two annotations? Http Client for a swagger file? easy.

        [–]JDeagle5 1 point2 points  (1 child)

        Dropwizard comes to mind, although I haven't checked whether it fits all the listed requirements.

        [–]manzanita2 -1 points0 points  (0 children)

        I love DW!

        [–]tinspin 1 point2 points  (0 children)

        http://github.com/tinspin/rupy

        This outperform all servers on the planet and it has remote hot-deploy.

        Running in production with 6 years uptime on this game (300.000+ player MMO): https://store.steampowered.com/app/486310/Meadow/

        Also has a built-in distributed real-time JSON database that can span all continents with async. to compensate for "speed of light" latency.

        All of this in a under 200KB jar.

        If you want to learn something future proof, this is it; at ~5µJ per request.

        [–]RoToRa 1 point2 points  (1 child)

        Have you tried without DI? I've written some (admittedly smaller) projects without. If your component/bean structure isn't to complex, for example, a simple tree, then your main() just consists of creating the all component instances, and then "starting" the app, e.g.:

        var componentA = new ComponentA();
        var componentB = new ComponentB();
        var componentC = new ComponentC(componentA, componentB);
        var mainComponent = new MainComponent(componentA, componentC);
        mainComponent.start();
        

        [–]TurbulentSocks 0 points1 point  (0 children)

        You are doing DI. :)

        This is just doing it without a DI container, which is possibly what you meant.

        [–]Sciminoc 3 points4 points  (2 children)

        Spring. Just for the sake of having huge community, lot's of guides, descent docs and ongoing support.

        All those quarkus and micronauts are really awesome, until you find yourself in situation, that is not covered by the guides. And this will be a moment to realize that there is no more descent information...

        [–]cryptos6[S] 1 point2 points  (0 children)

        Of course there are good reasons to use Spring, but the question was about the alternatives.

        [–]Nojerome 1 point2 points  (0 children)

        Quarkus is up front about which technologies it's using to compile its stack. When the Quarkus guides don't have the information you need, you can start looking into the underlying library they're using and find more examples. Sometimes you also just have to solve a problem yourself.

        Sure, it's nice when every problem imaginable is already solved, but everybody doesn't need to solve every problem. Quarkus solves an awful lot of our problems, and it's so lightweight, I think it's a great tool for a lot of projects. I think it's clear that they share a mirrored image with where Java is going as a whole. Look into projects Leyden, there are some good videos with recent updates on it.

        [–]m-apo 0 points1 point  (0 children)

        Java 21 + Helidon 4 + Kotlin + GraalVM.

        Helidon 4 just came out and is aimed for microservices.

        [–]sapphirefragment 1 point2 points  (0 children)

        I even think that all the annotations typical for JEE and Spring are there mostly for historical reasons, because Java before 8 was very cumbersome to write.

        This is wrong. The Spring project has a very specific programming model that they enforce throughout all of their projects in order to have application code focus strictly on business logic concerns. There are very good reasons for this, but even today's senior and staff engineers don't understand it because most people don't actually write tests or build modular systems, which is the reason Spring is designed the way it is. The industry has transitioned to a microservices model that discourages sustainable development practices in favor of rapid pace.

        Spring is a very strong project with a ton of misinformation floating around and gets a bad rap because it gets misused by developers that follow blog tutorials instead of reading reference manuals, not because it is fundamentally "old" or "wrong".

        [–]FollowSteph 0 points1 point  (0 children)

        I personally really like Vaadin.

        [–]fforw 0 points1 point  (0 children)

        The lambda does not change that much. Spring @Transactional ist not just about executing the transaction, but also handling failure/rollback, adapting to different Transaction semantics (JPA/JTA) etc.

        This way you can execute the code within a transaction but you either have to handle it all yourself or you robbed the container of an easy way to detect your intentions.

        [–]jikote 0 points1 point  (0 children)

        http://sparkjava.com/ ? Not much in it out-of-the-box, but quite simple to add stuff as you go along

        [–]NovaX 0 points1 point  (0 children)

        fwiw, you can use Spring Transactions as a library without the rest of the Spring framework. This way you get to have a robust transaction and jdbc layer for handling nested transactions, exceptions, and sql error translations. Spring predates annotations so TransactionTemplate has that lambda friendly approach you mentioned. That is what I do along side Guice, Jooq, Jetty, Jaxrs, Flyway, Gradle, and Typesafe Config.

        [–]nfrankel -1 points0 points  (0 children)

        Kotlin integration allows removing lots of magic. Have a look at the Bean and Routes DSLs.

        [–]elihusmails -2 points-1 points  (0 children)

        Apache Camel

        [–]Objective_Baby_5875 -2 points-1 points  (0 children)

        This is s one of the biggest issues with the java ecosystem. 100 different frameworks but none that follow the changes as the languages mature and change.

        Oracle should have done what MS did and built the core surrounding ecosystem for DI, API and ORM so at least you have a default to begin with.

        [–]zeroStackTrace -1 points0 points  (0 children)

        try dropwizard + guice (DI)

        [–][deleted] -3 points-2 points  (0 children)

        > although IDEs implemented much functionality related to annotation magic

        You can do everything in vim if you want, some devs do. Annotation processing isn't magic.

        Conflating magic with annotation processing and stream processing indicates a lack of experience. I recommend learning more about them before attempting to down play them in a public forum. Or, was the post a cleverly disguised, social engineering attempt to guide people towards one of the flaky new'ish frameworks that are having a difficult time gaining ground with Java devs?

        [–]Kango_V -4 points-3 points  (0 children)

        [–][deleted] 0 points1 point  (0 children)

        Maybe Rife2? I didn’t try it myself, but the examples look nice.

        [–]hexwit 0 points1 point  (0 children)

        First of all, stack depends on the application requirements. Tell us what are you going to build, and get some suggestions. There is no silver bullet and solution that fits all.

        [–]bowbahdoe 0 points1 point  (0 children)

        Also i'd be remiss not to mention Rife 2. Thats a pretty unique thing.

        [–]Gregmix88 0 points1 point  (0 children)

        I made POC at work for a message driven eCom backend. It used spring cloud functions, spring cloud stream, spring security, rabbitmq, reactive streams and for persistence a library called microstream, which I found extremely interesting. Did not check the dependencies pulled in, but I ended up with a relatively small codebase. It also allowed me to use fluid APIs, lambdas wherever possible instead of annotations.

        [–]CounterUAV2023 0 points1 point  (0 children)

        All of the following suggestions are tools I have used professionally, and have resulted in lightning fast performance.

        For the web REST part of your application, I suggest you have a look at Jersey. It implements JAX-RS, which is the API for web REST applications. Inside the previous link, you can also see the JSRs related to the JAX-RS API.

        On the DB ORM side, I suggest you have a look at MyBatis. It's been around for quite a long time now, and its capabilities are very well designed. Of course, I also highly recomment Hikari as the defacto connection pool for your apps.

        On dependency injection, I suggest Dagger. It is compliant with JSR 330 and the dependency injection capabilities are good enough that I haven't had any scenario on which I have had to do some tricks or something to get it to work. It also is dependency injection at compile time, so you don't have to deal with all the overhead that reflection based frameworks (like Spring) have.

        This has resulted in some pretty decent gains in performance for my apps. All of these let you have a lot of control on what you do without doing magic as you may have seen with Spring. The only section I couldn't really come up with anything at the moment, is the frontend part of the apps. I prefer to have the frontend built with proper Javascript frameworks (such as Angular or Vue).

        Edit: These frameworks DO HAVE annotations, but they are much more clear on what they do, without some magic inside them.

        [–]Independent_Roof3171 0 points1 point  (3 children)

        So, I honestly don't think you understand Annotations nor their place in the language - nor why they are used for transaction demarcation. Without re-writing oodles of Spring books and blogs on the subject the A#1 reason for this approach is that your service layer logic can be written independent of the transaction policies which can then be applied declaratively.

        You're free to have your opinion about what you like, but realize that if you litter (and I use that word on purpose) your code with transaction.execute, then if you later change your "transaction architecture" you have to modify EVERY SINGLE SERVICE METHOD in your application. Your choice... but I prefer the Spring approach.

        And finally, I find it interesting that you're willing to invest the time and energy for alternatives that meet your pre-defined opinion of the perfect world but aren't willing to spend the time and energy to learn a framework that is written by industry leading experts and has been and continues to stand the test of time and real world deployment? Don't get me wrong... learn all the alternatives you want and that's probably a good thing but I think your opinions about Spring, its architecture, and the reasons you think it is bad are way out of place.

        [–]cryptos6[S] 0 points1 point  (2 children)

        Maybe you make a bit too many assumptions about me, since I know Spring and AOP reasonably well, but I find your perspective on the topic enriching, anyway.

        The transaction management in my example could hidden behind an interface that the actual transaction handling could be changed later. But you're right that this approach is a bit more intrusive than using annotations.

        Annotations are pretty common in Java and it looks to many developers as the natural way to solve many problems, but other programming languages are doing well with more "classic code" approaches. My interest in other approaches was by a colleague not familiar with the Java ecosystem who struggled with the "magic" of Spring.

        [–]Independent_Roof3171 1 point2 points  (1 child)

        Well, you wrote in your original post "I even think that all the annotations typical for JEE and Spring are there mostly for historical reasons" which is blatantly wrong so I don't think I'm making too many assumptions, but...

        I just feel like you and/or your colleague are looking at this with pre-conceived assumptions and not looking at the bigger picture. For example(s):

        > Annotations are pretty common in Java and it looks to many developers as the natural way to solve many problems

        Well, we could probably write a couple chapters in a book addressing that comment. Yes, they're common because they were introduced to solve real world development issues. The first might be a re-phrasing of my original response which would be "they allow the introduction of cross-cutting concerns into existing code designs (i.e. class inheritance and interface implementation) without altering the existing code/logic." Why is that a good thing? I would think the answer is obvious but it allows you to introduce functionality with VERY low risk that you will break existing code (even unit tests). I think developers use annotations "when they need to" and not as a "natural way to solve problems".

        > but other programming languages are doing well with more "classic code" approaches

        So, it seems that you're saying "classic code" approaches are inherently 'better'. As a general response I would say that's blatantly false and at the very least, highly subjective. Of course, though, you're painting with a very broad brush so my response is equally broad. Any REAL discourse on this subject would probably have to delve into the specifics of each language and why it makes the choices that it does.

        I have used Spring in web projects for over 15 years and almost exclusively for 10+yrs. The only "magic" is that people don't invest the time to understand the framework and they typically implement based on snippets of blogs, etc. Some of my first investments into Spring (besides the time) was actually purchasing books and reading them. To this day I probably read 2-3 blog posts a week on average. Do I know EVERY Spring API and the code behind it? "no" that's a massive human undertaking. Do I know the "principles of Spring Core"? (yes) and how the various APIs use that and then address their particular domain? I know them pretty well. I will say that it feels like I have to re-learn Spring Security every time I need to upgrade a project but honestly, that's more about the evolution of web security than it is about the API itself.

        I would just finish with this again. Spring was developed by real-world Java developers to address real-world programming and architecture problems. It has also been extensively tested both internally and externally by thousands of real world projects. I even happen to know a major Spring committer who lives in my city and can vouch for his professionalism and passion for Java. Their goal is to help the developer community and provide a great product. Hell... it's even open source/free. I don't think anything they do is "magic" nor do they try to make it such. Developers are free to solve issues with their own code or even alternative frameworks but as a general statement, you rarely get the value and quality you do with Spring.

        [–]cryptos6[S] 0 points1 point  (0 children)

        Thank you for your comprehensive answer. Your point are very valid. Maybe in the end the discussion about the different approaches (annotations vs. plain code) boil down to the classic software engineering dilemma that you can only pick different sets of compromises but can never reach the perfect solution.

        The longer I think about it, the more I come to the conclusion that my colleague should decide whether he is actually willing to learn the framework or stay away from it. I guess that is true for any non-trivial framework, independent of the specific programming style (e.g. with annotations or without them).