So I have to build this as a special type of jar and then set up this other, rather opaque, set of stuff and deal with all sorts of nonsense ...
Now?
get("/hello", (a,b) -> "Hello World");
And we're done...So I have to build this as a special type of jar and then set up this other, rather opaque, set of stuff and deal with all sorts of nonsense ...
Now?
get("/hello", (a,b) -> "Hello World");
And we're done...The applications certainly got a lot more complex than that, but we never found ourselves in need of a magic annotation that you can't step through with your debugger.
This is all about simplicity. It's pretty clear how a get() function on the router which takes a route and a callback works, but it requires some work to understand how Spring magically scans all your classes looking for annotations and then builds parser based on that. It's quite unclear where all of the routes are coming from (since they can come from a class just about anywhere). You suddenly need special tools. And the worst thing that suffers is transparency. Ctrl-clicking/Cmd-clicking on an annotation in your favourite IDE never tells you what it does.
In comparison, a second-order function is a vastly simpler and more grkoable beast.
The point was just to show that the http server aspect of it is trivial to set up.
You can hook in whatever you want from there.
object MinimalApplication extends cask.MainRoutes{
@cask.get("/")
def hello() = "Hello World!"
initialize()
}
API design shamelessly stolen from Python's Flask framework @GetMapping("/hello") fun hello() = "Hello, World!" import static spark.Spark.get;
public class HelloWorld {
public static void main(String[] args) {
get("/hello", (req, res) -> "Hello World");
}
}
[1] http://sparkjava.com/ @SpringBootApplication
@RestController
class DemoApplication{
@GetMapping("/hello") fun hello() = "Hello, World!"
}
fun main(args: Array<String>) {
runApplication<DemoApplication>(*args)
}
And this taught me that the best sinatra clone in java isn't really worth it in terms of lines of code saved (we save what? 3 lines of code? 6 with the imports?) when compared to a full-blown web framework like spring boot.Would you care to do another one where we return a json response? I'd bet you will need a json mapper class for complex objects whereas I will return a dataclass instance and it will just work.
fun main(args: Array<String>) = run(*args) {
get { "Hello Kotlin" }
}
It's always easy to make a framework lightweight. But there is no argument that Spring requires a lot of tedious boilerplate in Java (some of which can be avoided with Kotlin), and annotations which are hard to understand.Lightweight frameworks don't really tell you "We do everything that Spring does in less lines", since at one point you'll ask them to make avocado toasts or something else that spring-bakery has a plugin for.
The real power of lightweight frameworks is their simplicity. This is not for everyone (that's why we've got Spring and Rails), but if everybody was fine with the tradeoffs that Spring makes, you'll see the same kind of frameworks ruling the Node.js and Go landscape.
The annotations I used were "this is a spring boot application" on top of a class and another which says "this is a rest controller" to start your hello world application and we only saved a few lines and introduced additional hidden complexity with sparkjava because we still don't have a way to handle json whereas it comes free with spring boot.
You've got another one that says "this is an injectable service" and another which says "this is a db entity" and with the "this is a configuration" you've got 99% of spring boot applications covered. Not sure what is so hard about the annotations. Maybe it has to do with "knowing more than just java/kotlin syntax" that puts people off?
Your Spring example immediately turns me off because it uses a bunch of annotations that could do pretty much anything (and I'd have to learn). Further, it uses kotlin which is not java - it's a valid choice but it's a more terse language in general (so not necessarily valid to compare against java examples).
Spark is straightforward and easy to read, it does one thing and it does it well, and it doesn't demand that I spend a lot of time thinking about anything other than what I'm trying to achieve. I have a lot of time for that.
For the record, with kotlin and skipping imports (of which there would only be one anyway) -
fun main(args: Array<String>) {
get("/hello") { req, res -> "Hello World" }
}
I do indeed find this simpler than your proposal upthread.This behavior which looks helpful at first glance, is very confusing. If your not proficient with Spring or spend hours reading the documentation you'll never understand that: 1. Your object lifetime is tied to the request. 2. The instance you see at the debugger is actually a subclass that redirects all call to the actual scoped object instance depending on a thread local variable (I guess?) 3. The proxy instance is either slow (JDK Proxy) or could cause you grief when you upgrade to the next version of Java (CGLIB). It's not clear which is which without some investigating.
I rather prefer to go with a lightweight framework + a sane DI framework and do something more explicit, e.g. create a RequestProvider<T> interface:
interface RequestProvider<T> {
get(request: Request): T
}
class MyController() {
val fooProvider: RequestProvider<Foo> by inject(name = "foo")
fun myHandler(request: Request) {
val requestScopedFoo = fooProvider.get(request)
}
}
This approach is more explicit, but I prefer it.How exactly does Guice differ in request- or session-scoped injections that makes it that much better?
I have no need for one of those, I'm good building some fairly simple microservices against spark without 'lazy client initialization' or any framework features.
That's kinda the point, it's a simpler toolset for a single purpose. You may have requirements that are made simpler for you by knowing the arcane ins and outs of a feature-rich framework.
Not everyone does, and bringing in said framework to achieve something simple in the name of "Maybe, in future, I may need this" is a prime route to an overcomplex, heavyweight mess. IMHO.
Maybe you've avoided Spring-related hell, but all the java devs I know who survived that era tend to groan whenever it's mentioned.