Readit News logoReadit News
Posted by u/moring 3 years ago
Show HN: Java REST without annotations, DI nor reactive streamsgithub.com/MartinGeisse/g...
grumpyrest is a Java REST server framework that does not use annotations, automatic dependency injection or reactive streams, and minimizes the use of reflection. I created this because I got fed up with annotation-mad frameworks that you cannot easily understand, step into or reason about. grumpyrest uses the type system to guide JSON mapping and validation, and (possibly virtual) threads for parallelism. It's for grumpy people who don't like what REST server programming in Java has become.

I made this because I intend to use it in one of my own projects, but at the same time I want to make it available to others to (hopefully) get some good ideas on how to extend it.

bedobi · 3 years ago
I'm a dev with 10+ years professional Java experience and something more like this is what I wish Java had always had. Ignore the other commenters who are being predictably and characteristically harsh and uncharitable.
misja111 · 3 years ago
Frameworks such as Spring used to be much more like this, until the annotation hype started to kick in somewhere around 2010. I always thought this was a bad idea. Sure, annotations work nice in a small demo app, but in a large application you want to have everything explicit and under your direct control.
bedobi · 3 years ago
> Frameworks such as Spring used to be much more like this

Not really. Spring has always had problems with pointless complexity and turning what should be compile time errors into runtime ones. Its original schtick was DI, which you've always been able to do by just... sending dependencies in through the constructor, lol? No framework or magic needed. The emperor really has no clothes and I wish more people would admit that.

ElectricalUnion · 3 years ago
The alternative was "effectively stringly-typed XML forest" that was only checked at runtime; even worse for tooling that the current annotation (and recursive/nested annotation in the case of Spring) thing modern Java is.
elric · 3 years ago
I think spring's giant XML config file was preferable to the annotation garbage that most people use these days. But both are shitty solutions in my book. I'm still not convinced that doing all this configuration and magic at runtime is a good idea. Most of what spring does in terms of dependency injection (and probably a bunch of configuration related things as well) should really be compile time steps. There are very few cases where you want to change the implementation of $foo at runtime, and being explicit about those few cases would be nice.
krzyk · 3 years ago
Spring used xml to configure that so no that similar.
AugustoCAS · 3 years ago
Something that people are missing about annotations: in order to test the annotated class/method one needs to start running extra code, sometimes a lot of extra code.

Using spring as a toxic example, many things have to be tested using @SpringBootTest which is incredibly slow to start. On top of that because of the use/abuse of @MockBean tests stop being thread safe. So one ends up with slow test that need to be run sequencially. I'm working in a 'start up' that went the spring boot way and quite simple services take 15+ minutes to run all their tests, which is insane.

On top of that, annotations make it impossible/very dificcult to know what code is actually executed (and also it not possible to navigate to the code in an IDE). As I rule of thumb, I'm always happy to swap one annotation for one or two lines code.

okeuro49 · 3 years ago
You would only use @SpringBootTest at the top of the testing pyramid.

Spring Boot provides "test slices", so you'd also be using @DataJpaTest or @WebMvcTest, which run a lot faster, as they don't boot the entire application.

ivan_gammel · 3 years ago
> On top of that, annotations make it impossible/very dificcult to know what code is actually executed (and also it not possible to navigate to the code in an IDE)

I have never understood this argument. What is exactly the problem with identifying the executed code?

darthbanane · 3 years ago
Some of the aspect oriented stuff like cacheable will add a proxy to the annotated bean which can break reasoning about the code.

If you inject the bean and call the method you will get caching (because you are using the proxy). If you call the method from within the bean itself however you're not using the proxy and you won't get caching.

It's stuff like this on steroids when you start mixing annotations that makes it really difficult to reason about the code.

moring · 3 years ago
How do you identify the executed code? I don't even know how to start. You cannot single-step into it from the annotation, nor can you select the annotation, "go to definition" and see the code. You can "find usages" for the annotation which gives you a lot of places that may or may not be the code that gets executed.

Imagine I'm looking at a class that is annotated. What is the next step to find the code that gets executed for the annotations?

gofreddygo · 3 years ago
Annotations lead to an undocumented interface. IDE's are incredibly unreliable at finding implementations from compiled libs. That is 80% of my frustration around annotations. There are no standards, no patterns, almost nothing to find details on why some annotation isn't working as expected and what it expects from the developer.
jakewins · 3 years ago
If you use a “dumber” imperative style framework, the way to find out what code is executed is to go-to-definition of the library code when you call it.

With an annotation-based framework, how do you do the same? You could find usages of the annotations, and then manually read the thousands of places “@GET” is referenced?

AugustoCAS · 3 years ago
Hi Ivan!

From my exprience there are multiple reasons - The main one: I've learned tons from reading code. The ability to jump into code that does X to see how it's implemented is worth a lot to me. This is something I love about the jvm ecosystem which is unfortunately not present in many other languages. - Many libraries/frameworks (Spring Data comes to mind) provide very leaky abstractions. Understanding how the underlying technology is used can make a big difference. - Address questions when the documentation is not clear enough. - And last: to discover bugs in libraries. This is not common, but it happens.

ElectricalUnion · 3 years ago
On the other hand, Spring is one of those frameworks that you can probably test most of your stuff without those test fixtures and just use the annotated classes as if they are plain classes.

That of course means you're limited to constructor based dependency injection (but most people should be using constructor based dependency injection, right? The @Autowired/@Inject "magic" rarely really helps anyone most of the time) and requires isolating side effects (and therefore those pesky side effect inducing annotations) from the rest of the business logic.

oppositelock · 3 years ago
This framework looks wonderful.

Some people have an aversion to "goto" statements, and Java annotations are even worse, they're a "comefrom" statement, where you end up executing code before or after your function based on this annotation, so it makes the code really annoying to follow.

Java examples which show trivial code annotated with @POST or @Path are not representative of production systems, where you may have a lot more annotations for your DOM, documentation, and in some cases, you actually have more annotation boilerplate than you have code in the handler/controller.

Having annotations interleaved within your logic makes it difficult to provide good API documentation, and it's hard to automatically refactor, because your boilerplate is interleaved with real code. With an approach like this grumpyrest, you can put all your machine generated code into a package, and simply connect it to your hand written code with a little bit of glue. It makes spec-driven development much easier.

OpenAPI is very popular, and annotation based frameworks make it more difficult to integrate with it. If you generate API docs automatically from code, as with JAX-RS, it's easy to break things by accident because nobody audits machine generated docs. If you reverse the approach, and do spec-driven development, you code review the API behavior, and the code follows, which is a better model, in my opinion. Grumpyrest looks like it makes integration with spec-driven workflows quite easy.

A word of caution to the author; if this takes off, you will be inundated with issues and PR's, since people will use this in ways you never dreamed of. I'm experiencing that kind of onslaught in something I open-sourced for Go for REST API's.

moring · 3 years ago
> Some people have an aversion to "goto" statements, and Java annotations are even worse, they're a "comefrom" statement, where you end up executing code before or after your function based on this annotation, so it makes the code really annoying to follow.

I like this comment so much because I would have described annotations as a "comefrom" myself... but then I probably read that somewhere and forgot about it.

> Grumpyrest looks like it makes integration with spec-driven workflows quite easy.

This is interesting to me because I always thought about it the code-first-generate-documentation way, and I always wondered if/how I can derive all the meta-data from the code which, admitted, annotations make much easier because they are statically accessible.

Doing it the spec-first way is something I should definitely consider.

> A word of caution to the author; if this takes off, you will be inundated with issues and PR's, since people will use this in ways you never dreamed of. I'm experiencing that kind of onslaught in something I open-sourced for Go for REST API's.

Thank you for the warning. Do you have any advice on how to prepare for that?

re-thc · 3 years ago
> Some people have an aversion to "goto" statements

That's because 1 of the 1st things they teach at school is that "goto" is bad, but no 1 really gets why (at the time). It just goes into their brains and this carries forward.

> Java examples which show trivial code annotated with @POST or @Path are not representative of production systems

That happens with every language though. There are disasters everywhere.

nomercy400 · 3 years ago
Regarding api docs, my experiences have steered me to generate-docs-from-code. The problem with writing api docs first and generate code after, is that writing api docs is a 'business' collaboration, which eventually is not done by developers. The code is a 'technical' model of that api contract. The developers are limited by the api-to-code generator and even more importantly, the limitations of the coding language.

As a result, the 'business' comes up with the api contract, discussed and approved by multiple departments and committees, before the 'technical' developers have to show it is impossible to implement with current technology.

lakomen · 3 years ago
What was it that you open sourced for Go? I'd like to take a look at it.
suchar · 3 years ago
The main issue with Java-based projects (possibly using Spring) is the amount of existing resources: there are thousands/millions of example projects, code snippets, answers on StackOverflow etc. and majority of them is very old (as far as software development is considered). Even fresh resource are often using outdated techniques.

Modern Java is pretty good (although Kotlin is a bit cleaner IMO), but you should really use Spring documentation (if you are using Spring) and avoid code snippets from SO/Github.

moring · 3 years ago
The issues that I see with Spring aren't really code snippets from SO, but the fact that annotations drop all the advantages that Java had as a language. Just two examples:

When you create an Object of the wrong class and try to pass it to a method, you get a compile-time error. When you use the wrong annotation, nothing happens during startup of your application... but you don't even know at which point in time something should happen. Or if.

When a method you call throws an exception, you can run the application in a debugger and single-step into the method, then single-step until the exception gets thrown. This doesn't always just solve the problem but more often than not it gives you a good indication. If an exception gets thrown due to an annotation, you get an enormous stacktrace from some code you have never seen and didn't even know was run, or why it was run, from a thread you have never seen, complaining about wrong parameters that you have never seen, passed from another method you have never seen.

delusional · 3 years ago
Another one of my favorites. When you make an API for a library it's usually pretty clear what the user can do with it. When you make an annotation API for a spring library it's evidently impossible to expect how the user will use it. Random feature of a library won't work because the context you're using their annotation in aren't compatible with whatever assumptions they made.
nunobrito · 3 years ago
These is just (another) reason for avoiding Spring. Whenever I'm tempted because of XY module that looks good, I'm reminded with feedback like yours that things are still the same.

Oh well, will continue using java far away from that framework.

atomicnumber3 · 3 years ago
I love java, and especially modern java, but I also love Ruby and python and the majority of my web dev has been in Rails.

I'm now working on a Java side project, and while typically in the past I've just done the backend in java and then used rails for the web UI and had them share a DB, I'm trying to see if I can use Java for the web part without going insane.

Part of the problem is that historically the big players in java web are HUGE enterprises that was to be able to have 50 teams all do a small part of a backend in parallel and then just deploy them all together. Thus was born the servlet API and application servers.

But there's so many assumptions and bizarre requirements that come out of trying to do this perverse form of engineering that the whole thing ends up nigh unusable for someone who could otherwise just "rails g" 85% of their project.

Jetty has always struck me as a bit of a middle man where if you want, you can do the servlet thing but it's also a production grade application framework that doesn't force you to do the java EE dance if you don't want to. Though there is some leakage. But it's a lot less magical than Spring and is also just the http server bits, not the rest of the db and view and etc.

But since virtual threads are pretty stable now, I really want to use them, and jetty is the first reasonably complete and robust option that seems to have included support for them.

So - you know how these things go. I'm currently writing an HTTP url path router that supports the rails syntax from routes.rb. And then I'm going to write a Handler implementation that wrangles all the database stuff and does convenient/terse parsing of params (like how rails folds path params, url params, and form params into a single params object) and rendering of responses (so I can render a json object without having to call Content.Sink.[...] and use gson all over the place.

It's meant to all be very non magical and you can step through the code in a debugger and not see a billion reflective invocations of methods. And I'm hoping I can make the API of my Handler convenient enough that you don't regret that it's not annotation magic-based.

Also - I know there are various attempts at easier/less annoying Java web things like vertx and such, but they a) don't support virtual threads yet, and b) many of them are small enough im worried they'll rot eventually. Jetty meanwhile isn't going anywhere.

suchar · 3 years ago
From my personal experience, the first example doesn't really happen: thankfully I rarely see people randomly throwing annotations at methods/classes hoping one of them will stick. For most of the time annotations are self-explanatory.

However, there are some real issues with annotations in Spring/Java: - Application will sometimes run just fine without annotation processor/interceptor. Think of `@EnableScheduling` in Spring: you won't know that `@Scheduled` is not working (because of missing `@EnableScheduling`) until you observe that method is not executed. In this case static code is a clear win. - Annotation order: not all annotation processors/interceptors in Spring support specifying order. Annotation order in the code doesn't matter: it is lost during compilation. Good luck figuring out what is applied first in a method with `@Retry`, `@Transactional` and `@Cached` - will retry be executed within transaction or each retry will have its own transaction? This also is easily solved with static code instead of annotations.

As for compile-time error vs runtime-error: personally I don't really care as long as there is any error (which is not always the case in the first example) during the build/test/init/assembly phase. When I'm writing SQL queries in the code, I'm getting SQL parsing/compilation errors during application runtime - but that's fine, because I've written SQL-s against DB execution engine. When I'm writing Spark SQL job, I'm getting errors during query planning phase - and that's also fine, because I'm writing code against Spark's execution engine. Writing annotations against "annotation execution engine" (annotation processor/interceptors) doesn't seem any different or wrong in principle. Although, there are things that could be improved.

Stacktraces: there are a few additional interceptor method calls in the stacktrace when annotations are in use, however, most of the complexity comes from library/framework structure and developer's familiarity with it. Spring covers a lot of use cases thus it has its share of complexity. I'm not sure if "Spring without annotations" would be noticeably easier to work with, although I assume that feature-parity with Spring (MVC) is not a goal of this project so it probably will be easier to understand.

Groxx · 3 years ago
>When you use the wrong annotation, nothing happens during startup of your application... but you don't even know at which point in time something should happen. Or if.

Probably worth noting that this depends entirely on the annotation - they can (and many do) run at compile time, and can provide very strong safety guarantees.

Many (most? all? I dunno) of the bloated server-side DI frameworks do not do this though, and I 100% agreed that it's can be a truly awful experience.

EdwardDiego · 3 years ago
At least we're seeing a movement towards compile time annotation processing. E.g., Micronaut, Quarkus, Dagger2.

Much better it fails at compile time.

paulddraper · 3 years ago
> you get an enormous stacktrace from some code you have never seen and didn't even know was run, or why it was run, from a thread you have never seen, complaining about wrong parameters that you have never seen, passed from another method you have never seen

Aka using a library

kmac_ · 3 years ago
Spring WebClient pseudo streaming interface is atrocious. Java has switch expression with pattern matching, but no, they had to create something completely perpendicular to the language. "Hey, let's reinvent a wheel, but it will be our better wheel" - and now we have a square egg.
horsestaple · 3 years ago
WebClient predates pattern matching.
ActorNightly · 3 years ago
Java programming paradigm is dead in the modern day. You needlessly write way more code that is needed, all without any benefit, relying on third party libraries for main functionalities that may or may not have egregious vulnerabilities like log4shell.

The build system also takes needlessly long, because of how many hacks it involves (Groovy being a language designed to fix Java, being used in Gradle build system which runs a whole Java VM just to compile code)

Hardware is cheap these days, developer time is more expensive. Use Node or Python.

klibertp · 3 years ago
Gradle got WAY better with Kotlin DSL. Groovy is a great scripting language with incredibly powerful runtime meta-programming features. If you used Groovy for a project, you could get an experience close to Ruby or Python.

However, Groovy is also a great scripting language with incredibly powerful runtime meta-programming features. In short, that means you're stuck inside often stripped down (Jenkins) or ill-conceived DSLs that you either know by heart, know someone who knows it, or are in for a world of hurt trying to do basically anything.

With Kotlin DSL - even though the stack got even more complex, including embedded scripting host inside embedded JVM and all that - you get auto-completion in the IDE and "go to definition". That resolves half the problem with Groovy, which is discoverability. The other half - the byzantine object model and PERL-like "there's more than 1 way to do it" - won't go away just by changing the scripting language. Still, it's better.

There's also the thing about versions and compatibility between Gradle versions, Kotlin versions, and plugins versions. Finding the right combination takes so much effort that seemingly nobody ever bother to update the build tools in projects. Unless there's a "build engineer", which sounds kind of dystopic, but after working with Gradle for half a year I have to admit that managing the builds properly is indeed a full-time job.

> Hardware is cheap these days, developer time is more expensive. Use Node or Python.

It's not that simple. Sometimes, latency matters. Sometimes you really need something to happen in 20ms. But then you won't be using Java, or what pjmpl would say, you wouldn't use the stock JVM, but something that provides AOT compilation.

There are so many dimensions you need to consider when choosing an implementation language for something, and Java can be an optimal choice in many situations. As unfortunate as I think it is, the problem is not technical, but cultural. People who started programming in Java will have this rigid, rule-based concept of what you can and cannot do. Their minds are semi-permanently stuck in Java-like mold. Since Java is so all-encompassing, they are never confronted on their beliefs. Echo chamber. Cargo culting. Prevalent in all monocultures. The problem is when they switch to another language and infect it with beliefs that stopped being well founded due to the changed circumstances. They do their best to fit the new language into Java-esque shape, no matter how pointless it seems.

Kotlin is the biggest victim of this. There's so clearly visible divide between "make Java great again" crowd vs. "it's actually a nice language, why not use it for what it is?" crowd. They produce drastically different libraries, have very different goals, and do very different projects. Different values, methods, and outcomes. In itself, it's maybe OK, but... try being stuck in the wrong camp... and stay sane.

Dead Comment

stickfigure · 3 years ago
This misses out on the main benefit of using annotations: The associated Java code is "just Java". Testing JAX-RS endpoints is just a matter of instantiating Java objects and calling methods on them. Testing grumpyrest endpoints would require mocking the requestCycle other low-level http-oriented classes.

Here's the JAX-RS equivalent of the demo:

    public class GreetingResource {
        @POST
        @Path("/make-greeting")
        public MakeGreetingResponse greet(final MakeGreetingRequest request) {
            if (request.addendum.isPresent()) {
                return new MakeGreetingResponse("Hello, " + request.name + "! " + request.addendum.getValue());
            } else {
                return new MakeGreetingResponse("Hello, " + request.name + "!");
            }
        }
    }
This is less noisy (no explicit parseBody) and much easier to test - you can just instantiate a GreetingResource and call the method, no mocking required.

moring · 3 years ago
Thanks for your feedback. I'll take that into account.

You are totally right about having to mock RequestCycle, which isn't good. Furthermore, RequestCycle isn't really mockable in its current state. I'm planning to solve both problems in a future version by making it mockable, providing standard mock implementations, and removing the dependency on other web objects (such as the servlet API) from code which is just using RequestCycle.

The main point behind grumpyrest is that a lot is _not_ "just Java": While the handler method you presented is, the way it is mounted isn't, nor how dependencies are located and injected, nor how the JSON is validated and mapped to objects and back.

chii · 3 years ago
> the way it is mounted isn't, nor how dependencies are located and injected, nor how the JSON is validated and mapped to objects and back.

the point of a framework is to hide some of that from you. The point of abstraction is that you _should not_ have to know how the server mounts the handlers, just that it does and it does it via a contract specified in the documentation.

stickfigure · 3 years ago
> the way it is mounted isn't, nor how dependencies are located and injected, nor how the JSON is validated and mapped to objects and back.

These are problems that every web application has to solve. You can use an existing framework or you can write your own. It might seem like there's a "hand-wire everything" option but in any mature system that turns into "write your own framework" as developers get tired of typing the same boilerplate over and over.

For example, I can tell you right now that the team is going to get tired of typing `requestCycle.parseBody()` at the top of almost every method. Some clever sod will eventually figure out how to use AOP to make it implicit. Just like JAX-RS.

javcasas · 3 years ago
So how do you test that the method, the path and the body parser are correct? I have had bugs in all of these three.
iovrthoughtthis · 3 years ago
TL;DR This is a bad example as we're mixing content construction with http service layer concepts. It should probably be more like:

    public class GreetingResource {
        @POST
        @Path("/make-greeting")
        public MakeGreetingResponse greet(final MakeGreetingRequest request) {
            return MakeGreetingResponse(Greeting(request.name, request.addendum));
        }

        public Greeting(string name, Value addendum) {
            if (addendum.isPresent()) {
                return "Hello, " + request.name + "! " + addendum.getValue();
            } else {
                return "Hello, " + request.name + "!";
            }
        }
    }
I think this is actually a little problematic. This handler is a likely location to mix http service logic with application logic and the interface exposed, via automatic parameter injection etc, implies the code in here should be application level but it's actually in the seam between then application and the http service layer.

Testing custom http service logic should involve mocking as it depends on objects and behaviours owned by the http service layer.

Code that we want to easily test for application level logic can be extracted into application level concepts.

rco8786 · 3 years ago
Kudos to you for trying this. Every time I open a Java project after spending time in literally any other language I get saddened by just how...cluttered? wordy? tedious? it is...hard to find the right word, but it's not good.
olavgg · 3 years ago
Of all web frameworks, with perhaps the exception of Ruby on Rails. I really struggle with lack of documentation or the quality of documentation. And lesser popular frameworks has a lot less volunteers sharing knowledge.

Spring Boot is one of the most popular web frameworks in the world. It is by far easier to figure out how to do build something that solves business problems in Spring / Hibernate than alternatives(except maybe RoR).

For example, do you want to use Micronaut, the Spring Boot killer? Good luck fetching a collection with string type. I takes basically 2 minutes to google how do this with Spring Boot / Hibernate, and it will take you a day or two to figure out it isn't possible at all with Micronaut without writing massive amount of code that binds the results from your SQL to your objects. This is one example, and it shows the madness in web frameworks. Why are we switching frameworks that only ends up slowing us down?

Spring Framework is a big framework, that solves many problems. It may be overwhelming the first year, but with a few years experience you do not want to switch, because other frameworks lacks or has ugly hacks for many Spring Framework features.

Other advantages, massive access to experts for hire. There are literally thousands of Spring Framework developers in my area. Also, since I am an expert myself, I can share my knowledge between these people, and together we are improving our knowledge at a rate other frameworks cannot offer and this gives us a massive innovation pace that brings increased business value.

The next time I will try another web framework, I need to see that my productivity gets improved immediately. Otherwise, is just noise.

nprateem · 3 years ago
Plus it's old enough that chat gpt is quite helpful. Would be good if they could update it for spring boot 3 though.
mhd · 3 years ago
I've been doing some Angular-/Nest-ish TypeScript projects, and it's basically Spring with more bugs and = signs.
re-thc · 3 years ago
> basically Spring with more bugs and = signs

The worst parts of Spring is Spring. Nest lacks the IDE, the performance in the JVM, etc... there is nothing to gain.

webosdude · 3 years ago
I haven’t used Angular but I have used Nest and I agree with this sentiment. Java Spring’s annotations are similar to Nest’s custom decorators.
Traubenfuchs · 3 years ago
As a year long spring (boot) dev, I felt right at home with angular 2+ -it‘s literally the spring framework of frontend frameworks.
winrid · 3 years ago
Vertx is pretty good. I have two vertx services in prod without a single annotation.

Dead Comment

jayd16 · 3 years ago
Wouldn't this add more cluttered boilerplate? Annotations are pretty clean looking but the backlash is from the "magic" they provide, not the clutter.
nunobrito · 3 years ago
Sure, other languages without semi-colons and using invisible tabs for syntax are fantastic. What I love best are magic object types where you only discover invalid type casting when running the code.

And lest we forget the fabulous unit testing for those non-tedious languages. Oh.. I forgot testing is tedious and therefore unavailable for most of those languages.

But hey, just look at that really short code without a single comment. The word you're looking for is: Fantasticc! :-)

rco8786 · 3 years ago
This doesn’t describe any language or framework I’ve worked in so hard not to conclude that it’s some sort of straw man
Phelinofist · 3 years ago
Looks a bit like Spark - https://github.com/perwendel/spark
moring · 3 years ago
I don't know why this was downvoted. Spark was actually one of the alternatives I considered before I concluded that I couldn't find any framework that suits me, and started writing grumpyrest.

The main issue I had with spark was, from what I could see, the lack of good JSON support. A major part of grumpyrest is its JSON serialization/deserialization framework (it's roughly half of the whole codebase!) which applies the same principles as grumpyrest does for REST, to JSON. (I even called it grumpyjson in anticipation that I might one day break this out as a standalone project).

Now don't get me wrong, I consider Jackson a high-quality framework, and I like very much how its author takes care of even the smallest details. It's not at all like Spring. However, in making it work as I wanted there were too many things that I could not solve to my satisfaction -- I could not abstract them in a way that was truly re-usable, and every API method would have to deal with these things again. This was even more true for Gson. So in the end, I used them (Gson, to be precise) as a low-level JSON library that basically translates between a JSON AST and serialized JSON, and did the high-level mapping to application classes myself.

marginalia_nu · 3 years ago
Hmm, a lot of my endpoints (in Spark) tend to look like

        public SomeService() {
           Spark.post("some/endpoint", this::someEndpoint, gson::toJson);
           Spark.get("another/endpoint/:id". this::anotherEndpoint, gson::toJson);
           //...
         }


        private ResponseType someEndpoint(Request request, Response response) {
           Something some = gson.fromJson(request.body(), Something.class);

           return new ResponseType(some.a, logic(some));
        }

        private ResponseType2 anotherEndpoint(Request request, Response response) {
           return new ResponseType2(otherLogic(request.param("id"));
        }
Like yeah I guess it could be have more well integrated json support, but it's not like this is heavy in boilerplate, and I do think it balances the need to occasionally access more low-level aspects of the HTTP stack well.

Not to detract from your project, of course.

winrid · 3 years ago
Weird, usually gson is super straightforward for me. I don't think you should be working with the JSON AST. Rather, have a class that maps to the JSON, which is a DTO, and then translate that to your app layer.
kasthack · 3 years ago
AlexITC · 3 years ago
I think we need more simple alternatives like this, https://javalin.io/ is another project I have been following which looks simpler to me.

In any case, thanks for sharing.

doctorpangloss · 3 years ago
Helidon Nima may wind up performing similarly to Netty. It has a straightforward API.

https://www.infoq.com/news/2022/09/introducing-helidon-nima/

https://github.com/tomas-langer/helidon-nima-example/blob/ma...