Also, java annotation processors are strictly "append-only", they can't change code written as is. They may subclass it, or build new classes that make use of the annotations.
In my experience LLMs are more than happy with annotations, especially from the widely used ones (spring/jakarta ee, lombok though it's not an annotation processor, etc).
If you think about it, an annotation like @Path("/endpoint") is very informative for both humans and LLMs alike, being local to what it attaches to. Within an agent, the code serving the endpoint will be immediately visible in the context returned by a simple string search, no need to do another round of "find wherever this codebase registers routes".
That metaprogramming is how a lot of places end up doing Java, because Java is a bad language that needs crutches like that. Or at least needed until whatever newer version fixed limitations of the old one, but all that old code is still around.
Biggest thing was lack of cooperative multitasking until virtual threads (Project Loom). And much older, lack of lambdas before Java 8.
It’s even simpler to have a “register” method that takes the path specification, the HTTP verb, and a function to handle the request.
There is no case where annotations are superior to the meta programming facilities built into the language proper. Annotations only became popular because Java didn’t have easy syntax for function references or anonymous functions for a very long time.
Also, hard disagree on "register" method being simpler. A register method is code, while an annotation is a static declaration, ergo data. The former can happen in a helper function, renaming it from "register" to "path", changing/modifying the parameters, or putting it into some while loop dynamically generating endpoints.
At the very extreme it is Turing complete to figure out what endpoints are registered.
10+ years of lambdas, but you can still tell from new code that the language used to not have lambdas. Plenty of code is older than that too.
The annotations are static, yeah. That's one advantage. I would still rather not do that. A lot of people were happy not to need that anymore in like NodeJS.
Any company that's 10 years old will have code that's 10 years old in every language they use. And every language has some flaw that was "fixed recently" but that's not relevant in a mature codebase. Like "Python packaging is fixed now with uv" no it's not. And especially anything to do with threading vs cooperative multitasking will stick around.
Mostly old code will keep working, but there are exceptions like Python 2->3 breakage that deserves all the criticism it got.
Also, java annotation processors are strictly "append-only", they can't change code written as is. They may subclass it, or build new classes that make use of the annotations.
In my experience LLMs are more than happy with annotations, especially from the widely used ones (spring/jakarta ee, lombok though it's not an annotation processor, etc).
If you think about it, an annotation like @Path("/endpoint") is very informative for both humans and LLMs alike, being local to what it attaches to. Within an agent, the code serving the endpoint will be immediately visible in the context returned by a simple string search, no need to do another round of "find wherever this codebase registers routes".