A Sinatra-inspired micro web framework for Java
sparkjava.com
sparkjava.com
Its most notable implementation is perhaps Jersey (https://jersey.java.net/documentation/latest/getting-started...), which is used, for example, by Dropwizard (mentioned in another comment).
Some of these implementations include important features like health and performance monitoring.
@Path("/hello")
public class HelloWorld {
@GET
public String get() {
return "Hello World";
}
}
Seems very Sinatra-like to me.I see the term "get" twice. The class name is redundant with the resource path. I suppose not a huge problem because many MVC frameworks require classes, but not even close to Sinatra.
Sinatra:
get '/hi' do
"Hello World!"
endHere is an example in Groovy using JAX-RS:
@Path("/hello")
class HelloWorld {
@GET
def sayHello() {
"Hello, world!"
}
}
Almost as clean. The braces and parens make it a bit uglier; but those are just part of the language. class Hello {
def get() {
"Hello, world!"
}
}
I would prefer to see this and then let someone have a routing config somewhere else if they want to move the /hello endpoint.I've never liked the separate routing config approach. Play Framework uses(d?) it in the 1.x branch and I always found it annoying.
Similarly old-world Servlets were done that way too. You'd put the routing information in an XML file and the container would read it at start up.
Further, not a big fan of annotations. Which is declarative programming for Java. In which case, just use a dynamic programming language.
I am a big fan of stepping thru code with a debugger. Which rules out programming via XML (eg Spring) and annotations.
Also, Python has decorators and Python 3 will soon have function annotations.
You misunderstand. Java breakpoints, yes. Spring breakpoints, no.
To troubleshoot Spring, the best you can do is trace (log) and inspect untyped nested hashmaps.
No thank you.
The IDE can sometimes pre-detect trivial errors. Whoopie.
Python has decorators and Python 3 will soon have function annotations.
My condolences.
eg:
@Path("/companies")
public class CompanyResource {
@GET
@Path("/{id}")
@Produces(MediaType.APPLICATION_JSON)
public Company getFromDB(@PathParam("id") String companyId) {
return SomeDatabase.get(companyId);
}
}
public class Company {
List<Person> employees;
}
public class Employee {
String name;
int age;
Employee manager;
}
You start to understand how good jax-rs and modern Java can be when you actually start using it for something useful. get(new JsonTransformer("/companies/:id") {
@Override
public Company handle(Request request, Response response) {
return SomeDatabase.get(request.params(":id"));
}
});
public class Company {
List<Person> employees;
}
public class Employee {
String name;
int age;
Employee manager;
}http://www.sparkjava.com/why.html
I have done JAX-RS, for small web apps where you aren't trying to build in the kitchen sink, Spark is looking nice. Spark doesn't seem to be trying to replace JAX-RS, it seems to just be making the syntax a bit easier and doing lightweight REST in a way I find unique and really applicable to small web apps. He uses plain Java main.
Well, I don't know... I'm sure Spark is great, but dropping a widely accepted, well established and quite liked standard just for an arguably "bit easier" syntax (especially when there haven't been any major complaints about the standard syntax) seems like the wrong tradeoff. I would have loved a JAX-RS implementation with other compelling features like performance, monitoring etc. Another good JAX-RS implementation is always welcome.
Sinatra:
get '/hi' do
"Hello World!"
end
Spark: public class HelloWorld {
public static void main(String[] args) {
get(new Route("/hello") {
@Override
public Object handle(Request request, Response response) {
return "Hello World!";
}
});
}
}I think the value here is in having a micro framework that allows you to put together a web app without having to juggle a horribly complex abstraction hierarchy for even the simplest of tasks.
Following your point about the cruft being from the language, Spring MVC is as "micro" as Spark. In fact, it is shorter.
Spring MVC:
@Controller
public class HelloController {
@RequestMapping(value = "/hello", method = RequestMethod.GET)
public @ResponseBody String hello() {
return "Hello World!";
}
}
Spark: public class HelloWorld {
public static void main(String[] args) {
get(new Route("/hello") {
@Override
public Object handle(Request request, Response response) {
return "Hello World!";
}
});
}
}Therefore,
Micro: http://www.sparkjava.com/readme.html
Not micro: http://docs.spring.io/spring/docs/3.2.x/spring-framework-ref...
The downside when using a micro framework is that you always walk a fine line between simplicity and code reuse. Because of this, as the application grows you do end up writing more code than with a complex framework because you slowly start reinventing the wheel -- this is the old argument you hear over and over (Flask vs Django, Sinatra vs Rails, BackboneJS vs AngularJS, etc.)
Hmm. How about:
public String GET_hello(Request req) {
return "Hello World";
}
The framework would use reflection to build the routing map.What's wrong with those Scala developers?
They could make beautiful frameworks and APIs, always start to create crazy method names.
> "org.scalatra" %% "scalatra-atmosphere" % "2.2.1",
> send(("author" -> "system") ~ ("message" -> "Only json is allowed") ~ ("time" -> (new Date().getTime.toString )))
What's wrong with them?!
And this is rather sad.
You got a language which allows you to write nearly litteral code and still build stuff only mathematicans can understand.
send(JSONSerialization.with(StringSerializer.class, DateTimeSerializer.class).serialize(JSONObjectFactory.put(PairFactory.of(String.class, String.class).getInstance("author", "system"), PairFactory.of(String.class, String.class).getInstance("message", "Only json is allowed"), PairFactory.of(String.class, DateTime.class).getInstance("time", new Date())).getInstance()))
no, it's just json4s dsl for constructing json. If you wanted, you could've used constructors yourself: send(pretty(render(JObject(List(JField("author", JString("system")), JField("message", JString("Only json allowed")), JField("time", JString(new DateTime().getTime().toString()))))
usually scala libraries come with an easy to read/write DSL version of the API along with a more verbose java-style API shown above. Many libraries don't document with a plenty of examples. But, it really takes 10 minutes to learn DSL version in many cases. And, it gives you wings. There are plenty of benefits of DSL. You can research online about them.Why do they have to name them ~ % %%, if they can name them ANYTHING. Just to make the writing shorter?
It's like using variable names like a, b, c, data, value etc.
I want readable code, not short code by hook or by crook...
it's okay to learn things.
Free documentation does not pay bills, books do. Assuming people don't pirate them.
@get('/hi')
String myMethod() {
return "Hello World!";
}
I made a prototype of this (including extracting arguments Sinatra-style, which I think is its coolest bit), and didn't encounter any serious problems with this approach.However, I have done 95% of my web development in Ruby due to the Sinatra and Rails frameworks. The developer experience is too good to ignore. I'm hoping this can replace my Sinatra use case ... I don't think the magic of Rails could ever be replicated in Java.
Compare (Spark):
public class HelloWorld {
public static void main(String[] args) {
get(new Route("/hello") {
@Override
public Object handle(Request request, Response response) {
return "Hello World!";
}
});
}
}
to (JAX-RS, which dropwizard uses) @Path("/hello")
public class HelloWorld {
@GET
public String get() {
return "Hello World";
}
}If Dropwizard lets me fall back to non-annotations, then awesome.
Really, five minutes ago I didn't know either of these projects existed, so right now I'm feeling a little giddy either way you slice it!
Why?
> You use annotations in place of java code, and while you can tweak java code you can't tweak what an annotation does or how it does it.
Why can't you tweak an annotation? Annotations are built into the language, the entire point of them is to allow code to detect their presence in the bytecode and thus react at runtime. e.g. wrap a method marked as @Transactional in a database transaction.
Edit: and they're hacky because they're magical--it's entirely not obvious what they're doing.
Annotations trade flexibility for succinctness and readability. That's often a great reasonable tradeoff and a good place to start, but you might find yourself ripping them out later.
More abstractly, one of the characteristics of object-oriented design is the use of polymorphic objects. APIs which require you to define monomorphic annotated classes violate this and lose generality as a result. They are effectively class-oriented or method-oriented rather than true OO.
Why would you want an API that breaks the flexibility of code by forcing it to be glorified XML?
But when I though how many lines some webapp I was writing would take in Clojure, I went to the corner of the room and cried.
My conclusion for now is that "first versions" should be written in dynamic languages.
Question for the community: I don't have enough experience to know how this stacks up against other servers out there. Also, how do the people HN enjoy using java as a webserver (lang-wise, scaling-wise, etc)?
Any feedback would be much appreciated!!
If you have time look at Scala (Scalatra/Play Framework) or Clojure (Ring). You can reduce the size of your codebase dramatically.
But in general, IMO, compile times shouldn't be a major factor in choosing a language; expressiveness and run-times are more important.
Not sure about that, I'm using C# to write office plugins and it takes forever to start up each time. Often I forget what I'm supposed to be looking at by the time it's started.
This is one reason Go is so appealing to many people. The compile times make it "feel" like ruby or python or php in terms of "hit refresh and the change is there" style of development. That is a huge difference from, hit save and wait a minute for my java project to compile, and push out to tomcat a minute later. Even with JRebel the best I've seen is a 2-5 second page change refresh cycle in Scala and a minimum 5 second test suite reload time using SBT.
Scala is a beautiful language, but compared to Go, it's a very slow dev cycle.
JBoss, Jetty and Tomcat are pretty good in terms of taking care of load in heavy sites.
Most JVMs (Oracle, IBM, Azul, Aonix, ...) are able to achieve very good performance levels.
There is the tooling one gets, not only in terms of IDE support, but also for monitoring the state of the server processes and how load is being affected.
Finally if Java the language, doesn't appeal you, there are plenty of languages that target the JVM as well.
But besides that, Java is extremely mature, has great tooling, huge community and of course an enormous ecosystem with all the third party tools and libraries that come with it. The language is a bit primitive (but improving with each release), and the 'enterprise consultant' mindset of complexity for its own sake can be a turn-off, but overall, yeah, I like using Java.
I mostly like Java, and find a lot of the criticisms to be somewhat misguided, or reducing to quibbling over minutiae. But the Java ecosystem has a lot going for it, and despite how some people think "enterprise-y" is a pejorative, a lot of those "enterprise" features are actually very handy when you're, well, building a serious enterprise solution. Sure, if you're building the n thousandth MVP of a new cat-picture-sharing site, you don't need Java. But if you're building Amazon.com (the ecommerce side, not AWS) you might just find that JTA, JMS, JMX, JAX-RS, and some of the other "enterprise-y" stuff in Java is pretty fucking useful.
From a scalability standpoint, using modern appservers, Java scales horizontally just fine. And since Java runs on just about everything from watches to IBM zSeries mainframes, it also scales vertically pretty well.
All of that said, I prefer to do my actual coding in Groovy, as opposed to "pure" Java, but Groovy is almost a strict superset of Java, just with nicer syntax and some new features. But whether you're using Groovy or Java, everything I said above still applies, since you're still part of that overall JVM ecosystem.
In a nutshell, I want a service lifecycle container which allows me to write small, lightweight, modular services which depend on each other. The container should provide for cross-cutting concerns like monitoring, management, configuration, logging, auditability (I have concrete definitions for these things -- they're not just abstract biz-speak to me). HTTP should be an out-of-the-box, optional module. A service which exposes another service via a RESTful interface and depends upon the HTTP service should be another. For my application, services which listen to multicast data streams are just as important interfaces to the world as JSON-over-HTTP-via-REST. I want to write the HelloWorld method body and be able to do stuff like: expose it via a RESTful interface, invoke it every N seconds, inject an interface exposing the HelloWorld contract into other services, etc. When I want to know how my HelloWorld service is performing, there's a pre-built web interface which provides New Relic-esque views. I'd like to capture audit trails of the transactional flows through my services from an origination point (HTTP call, scheduled job, etc.) so I can translate failures, poor performance, usage rates, etc. into meaningful information (I wrote a poor man's version of this myself, and it's been quite useful).
Does anything like this exist? I sure can't find it. Modern JBoss (now Wildfly) might actually be closer to my requirements than I think. Perhaps I should look at the work they're doing on Version 8.
Dropwizard packages together Jersey on top of Jetty with good monitoring, but doesn't take care of other stuff like multicast. Nothing prevents you from adding Netty/Grizzly into the mix, though.
Actually, the modularity, composability and cross-cutting concerns you mention suggest Spring – not lightweight by any means, but neither are your requirements :)
I think you can even use Jersey with Spring: http://www.infoq.com/articles/springmvc_jsx-rs
It's kind of a bastardization, but we have a pretty good mix of HTTP and not, so it's nice to standardize.
Groovy:
ratpack {
handlers {
get('hello') {
response.send "Hello world!"
}
}
}
It can also be used (with somewhat less brevity) in good, old-fashioned Java.An 0.9.0 release is expected in a few weeks and the project is undergoing rapid (and sometimes API-changing) development, but it looks very promising.
And there are good reasons for that - naming packages after internet domains prevents namespace clashes and is consistently used by most Java projects.
It's actually projects that diverge from this convention that stand out like a sore thumb, and many that did have adopted it eventually, like JUnit.
This was for a course in software project management with some time restraints, so only focused on getting it done.
[1] http://www.techempower.com/benchmarks/#section=data-r6&hw=ec...
In a similar vein is Google SiteBricks: http://sitebricks.org/#home
Slightly heavier weight but with more features (templating, annotations, etc). Depends on Guice.
In addition, some of their docs link to a Google Code page, which keeps some examples on its index too: https://code.google.com/p/spark-java/
Lastly, it appears they're using GitHub for actual code, and, while they have a Github wiki created, it has no information.
I wish I could stress just how important it is to have all of the docs in one centralized location. Somewhere along the line, one of the five places they have examples will get out of date, and it'll be difficult to play spot the differences when it's replicated everywhere.
True, Spark may not be better/more concise than JAX-RS, but fun to try anyway.
http://www.sparkjava.com/readme.html#title17
As for Heroku, I found this:
https://gist.github.com/Fitzsimmons/2490382
Generally, for a lot of apps the embedded Jetty webserver might be sufficient.