jooby-project / jooby Goto Github PK
View Code? Open in Web Editor NEWThe modular web framework for Java and Kotlin
Home Page: https://jooby.io
License: Apache License 2.0
The modular web framework for Java and Kotlin
Home Page: https://jooby.io
License: Apache License 2.0
Before:
get("/", () -> Body.ok());
After:
get("/", () -> Results.ok());
Result sounds and feel better
These two value resolver will give you access to com.typesafe.config.Config
and org.jooby.Locals
from handlebars templates.
See #26 for more details
Instances of org.jooby.Managed
will be started/stopped by Jooby. This mean any Guice o
The Managed.start
callback will be executed on every single Guice object, regarless of the scope.
The Manage.stop
callback will be executed on Singleton Guice objects, ONLY.
Alternative, any class method annotated with @PostContruct
and/or PreDestroy
will be supported too.
A jooby app should be able to be packaged as a WAR file. This will allow a jobby app to be deployed into a Servlet Container.
War generation will be done by the maven assembly plugin.
let handlebars helper to be injected by Guice:
{
use(new Hbs().with(Helpers.class));
}
public class Helpers {
@Inject
public Helpers(A a) {
this.a = a;
}
public String myHelper() {
return a.something();
}
}
Please note isn't require to inject a Helper, simple/small helper can be created easily with the configurer callback:
{
use(new Hbs().doWith((hbs, config) -> {
hbs.registerHelper("myhelper", (ctx, options) -> {
return ...;
});
hbs.registerHelpers(Helpers.class);
});
}
It'd be nice that when you run mvn jooby:run it printed something like:
Listening on: http://127.0.0.1:8080
That way if you have a console that parses output it becomes clickable and you avoid having to type the url in the browser manually.
Integrate with Jdbi:
Basic usage:
{
use(new Jdbi());
get("/", req {@literal ->} {
DBI dbi = req.require(DBI.class);
// ... work with dbi
});
get("/handle", req {@literal ->} {
try (Handle handle = req.require(Handle.class)) {
// ... work with dbi handle
}
});
}
Jdbi module require/extends https://github.com/jooby-project/jooby/tree/master/jooby-jdbc
script will be under etc/bin
dir. The scripts are going to be processed by zip distribution #9
Implementation of request scoped objects get tricky if we using a child injector per request...
Starting from 0.5.0 Request.Module
will be replaced by a RequestScoped
annotation (like the servlet module from Guice). But keep in mind jooby won't depends on servlet-module because that will introduce a transitive dependency to the Servlet API.
These properties should be present in any request by default:
these two vars must be saved as request locals:
assertEquals(req.path(), req.get("path"));
assertEquals(req.require(Config.class).getString("application.path"), req.get("application.path"));
Json.configure method will be renamed to Json.doWith. This is the jackson-module
add a mongodb module using the mongodb Java Driver and the Morphia library
application.conf
db=db = "mongodb://localhost/mydb"
MyApp.java
{
use(new MongoDB());
get("/list", req ->
req.require(Datastore.class).find(MyObject.class).asList();
);
}
Module must provide the following services: Datastore, Morphia and MongoClient.
The db
property is used to create a MongoClient.
given:
public class Mvc {
@GET
@Path("/")
public Object handle(Optional<String> value) {
return value.orElseThrow(()-> new Err(Status.BAD_REQUEST));
}
}
expected output when value is missing is 400 (bad request) but I got 500 (server error). This only occurs on MVC routes.
useful if grunt (or similar tools) is required in dev environment (development).
<plugin>
<groupId>org.jooby</groupId>
<artifactId>jooby-maven-plugin</artifactId>
<configuration>
<commands>
<command>
<name>npm</name>
<arguments>
<argmuent>install</argmuent>
</arguments>
</command>
<command>
<name>grunt</name>
<arguments>
<argmuent>local</argmuent>
</arguments>
<wait>false</wait>
</command>
</commands>
</configuration>
</plugin>
A call to: mvn jooby:run
will:
npm install
(blocking, wait = true)grunt local
(no blocking, wait = false)Commands section is optional but when present commands will be executed before the jooby app in the order they were provided
The application.path property control the default context path of the app, but today it doesn't work
This issue is related to #32. From request object it should be possible to seed a RequestScoped object:
user("*", req -> {
req.set(Type.class, new Type());
}
seed method(s) looks like:
Request set(final Class<?> type, final Object value);
Request set(final TypeLiteral<?> type, final Object value);
Request set(Key<?> key, Object value);
Today, they belong to current response. From now on, they should be available in the request
Configurer callback should have access to current config
Today, it is possible to access to path params, but not req params. It might be useful to allow initial req params
application.host property should default to: 0.0.0.0
It should be possible to import/reuse routes from an existing App, for example:
public class A extends Jooby {
{
get("/a/1", req -> ...);
}
}
public class B extends Jooby {
{
get("/b/1", req -> ...);
}
}
public class App extends Jooby {
{
use(new A());
use(new B());
}
}
App.java contains all the routes from A and B. Also, ONLY routes are imported (modules, parser, formatter, etc.. will be ignored)
Actual implementation let undertow to set content-length or transfer-encoding: chunked header on static resources. The asset handler should attempt to always set the content-length in order to improve response time performance
org.jooby.Body.Writer
must provides access to request locals (request attributes).
A good example is to allow access to config properties at the rendering phase:
{
get("*", (req, rsp) -> req.set("config", req.require(Config.class)));
}
Later at rendering stage, we can:
{{config.someProperty}}
the following properties allow to setup/configure jetty thread pool:
jetty.threads.min=10
jetty.threads.max=200
jetty.threads.timeout=60000
Introduce a new contract for dealing with param conversions:
interface ParamConverter {
Object convert(TypeLiteral<?> type, Object[] values, Context ctx);
}
Convert method will be executed every time we try to access a request parameter (either from explicit API or from a MVC handler):
get("/", req -> {
T value = req.param("myparam").to(T.class);
}
There will be built-in converters for primitives, strings, dates, enums, collections and optionals, but also classes with a public string constructor and/or static methods named: valueOf, fromString, fromName.
Any other new type must be done with a custom param converter:
{
param((type, values, ctx) -> {
if (type.getRawType() == T.class) {
// convert a raw value to T
return ...;
}
// no luck! ask next converter in the chain
return ctx.convert(type, values);
});
}
Param converter are executed in the order they were registered. The first param converter that matches/resolved a type wins.
support capturing groups on path vars (a.k.a index var)
get("/assets/**", req -> req.vars().get(0)); // /assets/js/jquery.js -> js/jquery.js
get("/:key/:value", req -> req.vars().get(0) + req.vars().get(1)); // /foo/var -> foo:bar
rename some methods of Mutant
:
req.param("name").stringValue() will be req.param("name").value()
req.param("name").enumValue() will be req.param("name").toEnum(...)
<dependency>
<groupId>com.ning</groupId>
<artifactId>async-http-client</artifactId>
</dependency>
vs
<dependency>
<groupId>com.ning</groupId>
<artifactId>async-http-client</artifactId>
<scope>test</scope>
</dependency>
hotswap will be done at JVM level with: http://dcevm.github.io/
A java agent it's require to "restart" some statically binded services (like routes, ORM mappings, etc.)
A good alternative for the custom agent could be: https://github.com/HotswapProjects/HotswapAgent
ERROR [2014-11-27 11:11:58,264] execution resulted in serious error
java.lang.NullPointerException: A reason is required.
at java.util.Objects.requireNonNull(Objects.java:228) ~[na:1.8.0]
at org.jooby.WebSocket$CloseStatus.of(WebSocket.java:160) ~[classes/:na]
at org.jooby.internal.jetty.JettyWebSocketHandler.onWebSocketClose(JettyWebSocketHandler.java:84) ~[classes/:na]
at org.eclipse.jetty.websocket.common.events.JettyListenerEventDriver.onClose(JettyListenerEventDriver.java:79) [websocket-common-9.2.5.v20141112.jar:9.2.5.v20141112]
at org.eclipse.jetty.websocket.common.WebSocketSession.notifyClose(WebSocketSession.java:342) [websocket-common-9.2.5.v20141112.jar:9.2.5.v20141112]
at org.eclipse.jetty.websocket.common.WebSocketSession.onConnectionStateChange(WebSocketSession.java:374) [websocket-common-9.2.5.v20141112.jar:9.2.5.v20141112]
at org.eclipse.jetty.websocket.common.io.IOState.notifyStateListeners(IOState.java:185) [websocket-common-9.2.5.v20141112.jar:9.2.5.v20141112]
Once #34 get done it should be pretty easy to add a new web server, like http://netty.io/
With the addition of #44 it is pretty straightforward to use http://www.webjars.org/:
assets("/js/**", "/META-INF/resources/webjars/{0}");
GET /js/jquery/2.1.3/jquery.js
Short/custom mapping:
assets("/js/lib/*-*.js", "/META-INF/resources/webjars/{0}/{1}/{0}.js");
GET /js/lib/jquery-2.1.3.js
{
use(new Ftl());
get("/", req -> View.of("index", "model", new MyModel());
}
In addition to the fat jar distribution, a zip with the following structure should be created too:
public/
config/
logs/
tmp/
start.sh
stop.sh
myapp.jar
Zip distribution should be created with Maven, while executing: mvn clean package
HTTP session should work quite similar to: https://github.com/expressjs/session and must not depends on the target web server (jetty, undetown, etc..)
req params/headers can be injected in any of these classes:
public interface Person {
String name();
int age();
}
public class Person {
public final String name;
public final int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
}
public class Person {
private String name;
private int age;
public String name() {
return name;
}
public int age() {
return age;
}
}
retrieval is done using the req.body or req.params method:
// POST or PUT
Person person = req.body(Person.class);
// GET, etc.
Person person = req.params(Person.class);
or from MVC method
@GET
public Object params(Person person) {
...
}
@POST
public Object body(Person person) {
...
}
motivation:
There are some benchmarks too: http://www.techempower.com/benchmarks/ where undertow seems to perform better than Jetty. Those benchmarks are not the main reason of choosing undertow (reasons were described before). Jetty is a high performance server too.
Today a view model can be anything:
get("/", View.of("view-name", new Model());
From now on, it must be a Map
get("/", () -> View.of("view-name", "model", new Model());
// or
get("/", () -> {
Map<String, Object> model = new HashMap<>():
model.put("model", model);
return View.of("view-name", model);
});
There is a bug while starting two db connection from the jdbc-module.
db = mem
db.audit = mem
The two properties collide each other and the db = mem
value is lost.
The correct way of defining two databases will be:
db.main = mem
db.audit = mem
with the following java code:
{
use(new Jdbc("db.main"));
use(new Jdbc("db.audit"));
}
start.sh MUST set the -Dapplication.env=$APP_ENV
property
A web server should be pluggable so in the future Jooby can be package as war and be deployed into a Server Container.
This also will allow to provide multiples server implementation (undertow, netty, jetty, servlets) and let people to choose the best for them
Integrate and support Quartz Scheduler
a common example is to have a create/update handler where the id is optional for create and present for update, something like:
post("/model", "/model/:id", req -> {
Optional<String> id = req.param("id").toOptional(String.class);
...
});
In addition org.jooby.mvc.Path
should support multiples patterns too:
@Path({"/model", "/model/:id"})
@GET
public Object createORUpdate(Optional<String> id) {
...
}
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.