Lombok requires that you use a supported build system and IDE and while all the currently relevant ones are supported that is no guarantee. Needs plugins and agents that support your various tools' versions including the JVM itself. I've been in that hell before with AspectJ and the aspectJ compiler vs eclipse plugin (version incompatibilities that made it impossible to work efficiently until they fixed it all up).
Disclaimer: last company we used Lombok. Current company we are switching certain things to Kotlin instead. data classes FTW for example. I do miss magic builders. Builders are awesome. Building the builder is tedious ;)
Spring on the other hand... autowired values everywhere, and at least for me (who doesn’t work with Spring day in and day out) it’s very difficult to understand where they come from.
We do use spring and I've used it for a very long time now. Nothing is magic and not understandable about wiring if you do it right. Unfortunately there are a lot of projects out there that use it in exactly the wrong way if you ask me and then I'd agree with you.
I used to be in a company where we used XML config and everything was wired explicitly. The XML part sucked but with SpringIDE (eclipse at the time) it was Ctrl-clickable to find what's what.
We use Java config with Spring at my current company and I can Ctrl-click my way through it all and find what's what. There's a small corner of 'package-scan'ed stuff that is evil but we are cleaning that up.
Aside from the fact Java only released non-preview support for records one month ago, they:
- Don't support inheritance
- Can't be mutable
- Don't have a copy method
While Java records are nice, Kotlin data classes are strictly more capable than Java records.Copying objects is a well known need and there are countless libraries that try to help you with it. All with their own problems, notably runtime errors vs. compile time safety or pervasive use of reflection.
match msg with
| IncreaseCounter cnt ->
{ model with Count = model.Count + cnt }
| DecreaseCounter cnt ->
{ model with Count = model.Count - cnt }
| ResetCounter ->
{ model with Count = 0 }
| ChangeRubric name ->
{ model with Rubric = name, Count = 0 }
The "with" says: copy the original record by value, but change these fields. For completeness' sake: F# also has implicit returns, so the bit between brackets is the function's return value.For the rest, I agree that in 99% of the cases inheritance and mutability are not needed if you're using greenfield Kotlin libraries. But they are unfortunately often necessary in the Java world.
Mutable data classes are especially quite useful for reducing boilerplate when creating classes that implement the Fluent Builder pattern, which is unfortunately quite necessary if you don't have a copy method...
It's been years since I did any of that, as Lombok and spring boot generate that code for you.
Immutable classes get a @Value and maybe @Builder annotation, muteable ones get @Setters etc.
Springs auto wiring for beans is sadly magical however, so much harder to figure out what went wrong if you have any issues...