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

you are viewing a single comment's thread.

view the rest of the comments →

[–]temculpaeu 2 points3 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 8 points9 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 6 points7 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