diff --git a/.gitignore b/.gitignore index d6914784bb..fcb758a69d 100644 --- a/.gitignore +++ b/.gitignore @@ -24,4 +24,5 @@ jacoco.exec node dump TODO.md -.interp \ No newline at end of file +.interp +.factorypath \ No newline at end of file diff --git a/.travis.yml b/.travis.yml index 54baf1d3cf..92c1316669 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,11 +9,11 @@ before_install: - export MAVEN_OPTS=-Xmx1024m jdk: - - oraclejdk8 + - openjdk8 branches: only: - - master + - 1.x script: - ./build/travis.sh diff --git a/README.md b/README.md index 935899f837..2b8eeac82d 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ -[![Maven Central](https://maven-badges.herokuapp.com/maven-central/org.jooby/jooby/badge.svg)](https://maven-badges.herokuapp.com/maven-central/org.jooby/jooby) -[![javadoc](https://javadoc.io/badge/org.jooby/jooby.svg)](https://javadoc.io/doc/org.jooby/jooby/1.5.0) +[![Maven](https://img.shields.io/maven-metadata/v/http/central.maven.org/maven2/org/jooby/jooby/maven-metadata.xml.svg)](http://mvnrepository.com/artifact/org.jooby/jooby/1.6.6) +[![javadoc](https://javadoc.io/badge/org.jooby/jooby.svg)](https://javadoc.io/doc/org.jooby/jooby/1.6.6) [![Become a Patreon](https://img.shields.io/badge/patreon-donate-orange.svg)](https://patreon.com/edgarespina) [![Build Status](https://travis-ci.org/jooby-project/jooby.svg?branch=master)](https://travis-ci.org/jooby-project/jooby) [![coveralls.io](https://img.shields.io/coveralls/jooby-project/jooby.svg)](https://coveralls.io/r/jooby-project/jooby?branch=master) diff --git a/build/release.sh b/build/release.sh index fd80b8da72..cb7a424c2f 100755 --- a/build/release.sh +++ b/build/release.sh @@ -2,9 +2,9 @@ mvn -pl '!modules/coverage-report' clean deploy -P sonatype-oss-release -cd modules/jooby-bom +# cd modules/jooby-bom -groovy bom.groovy > pom.xml +# groovy bom.groovy > pom.xml # mvn -Dalpn-boot-version=$ALPN_VERSION clean deploy -P sonatype-oss-release -mvn clean deploy -P sonatype-oss-release +# mvn clean deploy -P sonatype-oss-release diff --git a/doc/available-modules.md b/doc/available-modules.md index 076d85cc32..c14b1e4de4 100644 --- a/doc/available-modules.md +++ b/doc/available-modules.md @@ -20,6 +20,7 @@ * [ehcache](https://github.com/jooby-project/jooby/tree/master/jooby-ehcache/#session-store): HTTP session store for {{ehcache}}. ## sql +* [expose](https://github.com/jooby-project/jooby/tree/master/jooby-expose): [Exposed](https://github.com/JetBrains/Exposed) is a prototype for a lightweight SQL library written over JDBC driver for Kotlin language * [jdbc](https://github.com/jooby-project/jooby/tree/master/jooby-jdbc): high performance connection pool for jdbc via {{hikari}}. * [jdbi](https://github.com/jooby-project/jooby/tree/master/jooby-jdbi): fluent API for JDBC. * [flyway](https://github.com/jooby-project/jooby/tree/master/jooby-flyway): database migrations via {{flyway}}. diff --git a/doc/doc/assets-autoprefixer/autoprefixer.md b/doc/doc/assets-autoprefixer/autoprefixer.md index 7cf4e35890..3cafcb8d35 100644 --- a/doc/doc/assets-autoprefixer/autoprefixer.md +++ b/doc/doc/assets-autoprefixer/autoprefixer.md @@ -9,7 +9,7 @@ ```xml org.jooby - jooby-assets-auto-prefixer + jooby-assets-autoprefixer {{version}} provided diff --git a/doc/doc/exposed/exposed.md b/doc/doc/exposed/exposed.md new file mode 100644 index 0000000000..13f9bdc30d --- /dev/null +++ b/doc/doc/exposed/exposed.md @@ -0,0 +1,49 @@ +# exposed + + Exposed is a prototype for a lightweight SQL library written over JDBC driver for Kotlin language + +> NOTE: This module depends on [jdbc](https://github.com/jooby-project/jooby/tree/master/jooby-jdbc) module. + +## exports + +* Database object + +## usage + +```java +{ + use(Jdbc()) + use(Exposed()) + + get("/db") { + val db = require(Database::class) + transaction (db) { + // Work with db... + } + } + } +``` + +## multiple databases + +```java +{ + use(Jdbc("db1")) + + use(Jdbc("db2")) + + use(Exposed("db1")) + + use(Exposed("db2")) + + get("/db") { + val db1 = require("db1", Database::class) + // Work with db1... + + val db2 = require("db2", Database::class) + // Work with db2... + } +} +``` + +That's all! Happy coding!!! diff --git a/doc/doc/hbv/hbv.md b/doc/doc/hbv/hbv.md index 8664f1675e..8f1d512c05 100644 --- a/doc/doc/hbv/hbv.md +++ b/doc/doc/hbv/hbv.md @@ -35,6 +35,19 @@ Bean validation via [Hibernate Validator](hibernate.org/validator). }); } ``` +### in combination with JSON parser +Jooby does not have a validation API or a validation API for HTTP bodies. Instead, this validator _wraps_ existing body parsers as they simply return the first deserialized object. Consequently, this module must be imported _before_ you import any parser! +If you were to use the [Jackson JSON parser module](../jackson/jackson.md) it would look like this: + +```java +{ + // must be imported before any body parser + use(new Hbv()); + use(new Jackson()); + + // routes go here +} +``` ## automatic validations of HTTP params and body diff --git a/doc/doc/micrometer/micrometer.md b/doc/doc/micrometer/micrometer.md index ad334cd8d2..0add2c9b67 100644 --- a/doc/doc/micrometer/micrometer.md +++ b/doc/doc/micrometer/micrometer.md @@ -78,6 +78,15 @@ import org.jooby.micrometer.PrometheusHandler; } ``` +> NOTE: for each additional registry, you must add the corresponding `micrometer` depedency. For Prometheus: + +```xml + + io.micrometer + micrometer-registry-prometheus + +``` + ## timed annotation Jooby supports the ```io.micrometer.core.annotation.Timed``` annotation for MVC routes: diff --git a/doc/doc/parser-and-renderer/parser-and-renderer.md b/doc/doc/parser-and-renderer/parser-and-renderer.md index d36723d567..e909fd8ab5 100644 --- a/doc/doc/parser-and-renderer/parser-and-renderer.md +++ b/doc/doc/parser-and-renderer/parser-and-renderer.md @@ -37,3 +37,7 @@ JSON support via [jackson](/doc/jackson). ## gson JSON support via [gson](/doc/gson). + +## yasson + +JSON support via [yasson](/doc/yasson). diff --git a/doc/doc/yasson/README.md b/doc/doc/yasson/README.md new file mode 100644 index 0000000000..abc9305c7e --- /dev/null +++ b/doc/doc/yasson/README.md @@ -0,0 +1,57 @@ +# yasson + +JSON support via [yasson](https://github.com/eclipse-ee4j/yasson) library. + +## exports + +* [json-b](http://json-b.net/users-guide.html) +* [Parser](/apidocs/org/jooby/Parser.html) +* [Renderer](/apidocs/org/jooby/Renderer.html) + +## dependency + +```xml + + org.jooby + jooby-yasson + {{version}} + +``` + +## usage + +```java +import org.jooby.json.Yasson; + +{ + use(new Yasson()); + + // sending + get("/my-api", req -> new MyObject()); + + // receiving a json body + post("/my-api", req -> { + MyObject obj = req.body(MyObject.class); + return obj; + }); + + // direct access to Jsonb + get("/access", req -> { + Jsonb jsonb = require(Jsonb.class); + // ... + }); +} +``` + +### configuration + +If you need a special setting or configuration for your [json-b](http://json-b.net/users-guide.html): + +```java +{ + use(new Yasson().doWith(builder -> { + builder.withFormatting(true); + // ... + }); +} +``` diff --git a/doc/fatjar.md b/doc/fatjar.md index ec239933cc..6d80423ac7 100644 --- a/doc/fatjar.md +++ b/doc/fatjar.md @@ -39,7 +39,7 @@ buildscript { } } dependencies { - classpath "com.github.jengelman.gradle.plugins:shadow:1.2.4" + classpath "com.github.jengelman.gradle.plugins:shadow:4.0.1" } } diff --git a/doc/quickstart.md b/doc/quickstart.md index 95708c36e8..eb6f3ca8db 100644 --- a/doc/quickstart.md +++ b/doc/quickstart.md @@ -17,7 +17,7 @@ requirements quickstart ===== -Just paste this into a terminal (make sure [Java 8](http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html) and [Maven 3.x](http://maven.apache.org/download.cgi) are installed): +Just paste this into a terminal (make sure you are in an empty folder, and [Java 8](http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html) and [Maven 3.x](http://maven.apache.org/download.cgi) are installed): ```bash mvn archetype:generate -B -DgroupId=com.mycompany -DartifactId=my-app -Dversion=1.0-SNAPSHOT -DarchetypeArtifactId=jooby-archetype -DarchetypeGroupId=org.jooby -DarchetypeVersion={{version}} diff --git a/jooby/pom.xml b/jooby/pom.xml index 552a2d1d56..127dc18af6 100644 --- a/jooby/pom.xml +++ b/jooby/pom.xml @@ -6,7 +6,7 @@ org.jooby jooby-project - 1.5.1-SNAPSHOT + 1.6.9 4.0.0 diff --git a/jooby/src/main/java/org/jooby/Err.java b/jooby/src/main/java/org/jooby/Err.java index cb202aa0ae..a8f04aaac7 100644 --- a/jooby/src/main/java/org/jooby/Err.java +++ b/jooby/src/main/java/org/jooby/Err.java @@ -203,9 +203,10 @@ */ package org.jooby; -import java.util.LinkedHashMap; -import java.util.Map; -import java.util.Optional; +import java.util.*; +import java.util.function.BiFunction; +import java.util.function.Function; +import java.util.function.Supplier; import com.typesafe.config.Config; import org.jooby.funzy.Try; @@ -287,12 +288,21 @@ public void handle(final Request req, final Response rsp, final Err ex) throws T log.error("execution of: {}{} resulted in exception\nRoute:\n{}\n\nStacktrace:", req.method(), req.path(), req.route().print(6), ex); Config conf = req.require(Config.class); + Env env = req.require(Env.class); boolean stackstrace = Try.apply(() -> conf.getBoolean("err.stacktrace")) - .orElse(req.require(Env.class).name().equals("dev")); + .orElse(env.name().equals("dev")); + + Function xssFilter = env.xss("html").compose(Objects::toString); + BiFunction escaper = (k, v) -> xssFilter.apply(v); + + Map details = ex.toMap(stackstrace); + details.compute("message", escaper); + details.compute("reason", escaper); + rsp.send( Results - .when(MediaType.html, () -> Results.html(VIEW).put("err", ex.toMap(stackstrace))) - .when(MediaType.all, () -> ex.toMap(stackstrace))); + .when(MediaType.html, () -> Results.html(VIEW).put("err", details)) + .when(MediaType.all, () -> details)); } } diff --git a/jooby/src/main/java/org/jooby/Jooby.java b/jooby/src/main/java/org/jooby/Jooby.java index 7f75ee7f77..a366b4194d 100644 --- a/jooby/src/main/java/org/jooby/Jooby.java +++ b/jooby/src/main/java/org/jooby/Jooby.java @@ -1363,7 +1363,11 @@ public Route.Definition use(final String path, final Route.OneArgHandler handler @Override public Route.Definition get(final String path, final Route.Handler handler) { - return appendDefinition(GET, path, handler); + if (handler instanceof AssetHandler) { + return assets(path, (AssetHandler) handler); + } else { + return appendDefinition(GET, path, handler); + } } @Override diff --git a/jooby/src/main/java/org/jooby/Request.java b/jooby/src/main/java/org/jooby/Request.java index 7232bb2521..7d166f8686 100644 --- a/jooby/src/main/java/org/jooby/Request.java +++ b/jooby/src/main/java/org/jooby/Request.java @@ -440,7 +440,13 @@ public List files(final String name) throws IOException { return req.files(name); } - @Override + @Nonnull + @Override + public List files() throws IOException { + return req.files(); + } + + @Override public Mutant header(final String name) { return req.header(name); } @@ -1085,6 +1091,16 @@ default Optional ifFile(final String name) throws IOException { @Nonnull List files(final String name) throws IOException; + /** + * Get a list of files {@link Upload} that were uploaded in the request. The request must be a POST with + * multipart/form-data content-type. + * + * @return A list of {@link Upload}. + * @throws IOException + */ + @Nonnull + List files() throws IOException; + /** * Get a HTTP header. * diff --git a/jooby/src/main/java/org/jooby/Response.java b/jooby/src/main/java/org/jooby/Response.java index 8ff89cb421..6dc0f9c7af 100644 --- a/jooby/src/main/java/org/jooby/Response.java +++ b/jooby/src/main/java/org/jooby/Response.java @@ -416,6 +416,14 @@ public String toString() { return rsp.toString(); } + @Override public boolean isResetHeadersOnError() { + return rsp.isResetHeadersOnError(); + } + + @Override public void setResetHeadersOnError(boolean value) { + this.setResetHeadersOnError(value); + } + /** * Unwrap a response in order to find out the target instance. * @@ -848,4 +856,18 @@ default Response status(final int status) { * @see Route.After */ void complete(Route.Complete handler); + + /** + * Indicates if headers are cleared/reset on error. + * + * @return Indicates if headers are cleared/reset on error. Default is true. + */ + boolean isResetHeadersOnError(); + + /** + * Indicates if headers are cleared/reset on error. + * + * @param value True to reset. + */ + void setResetHeadersOnError(boolean value); } diff --git a/jooby/src/main/java/org/jooby/Route.java b/jooby/src/main/java/org/jooby/Route.java index 94172045d7..0e3ae2cdab 100644 --- a/jooby/src/main/java/org/jooby/Route.java +++ b/jooby/src/main/java/org/jooby/Route.java @@ -1636,6 +1636,7 @@ class AssetDefinition extends Definition { public AssetDefinition(final String method, final String pattern, final Route.Filter handler, boolean caseSensitiveRouting) { super(method, pattern, handler, caseSensitiveRouting); + filter().setRoute(this); } @Nonnull diff --git a/jooby/src/main/java/org/jooby/handlers/AssetHandler.java b/jooby/src/main/java/org/jooby/handlers/AssetHandler.java index 6345844646..d9217329ca 100644 --- a/jooby/src/main/java/org/jooby/handlers/AssetHandler.java +++ b/jooby/src/main/java/org/jooby/handlers/AssetHandler.java @@ -206,7 +206,6 @@ import com.google.common.base.Strings; import com.typesafe.config.ConfigFactory; import com.typesafe.config.ConfigValueFactory; -import static java.util.Objects.requireNonNull; import org.jooby.Asset; import org.jooby.Err; import org.jooby.Jooby; @@ -229,6 +228,8 @@ import java.util.Date; import java.util.Map; +import static java.util.Objects.requireNonNull; + /** * Serve static resources, via {@link Jooby#assets(String)} or variants. * @@ -287,6 +288,12 @@ private interface Loader { private int statusCode = 404; + private String location; + + private Path basedir; + + private ClassLoader classLoader; + /** *

* Creates a new {@link AssetHandler}. The handler accepts a location pattern, that serve for @@ -315,7 +322,9 @@ private interface Loader { * @param loader The one who load the static resources. */ public AssetHandler(final String pattern, final ClassLoader loader) { - init(Route.normalize(pattern), Paths.get("public"), loader); + this.location = Route.normalize(pattern); + this.basedir = Paths.get("public"); + this.classLoader = loader; } /** @@ -345,7 +354,9 @@ public AssetHandler(final String pattern, final ClassLoader loader) { * @param basedir Base directory. */ public AssetHandler(final Path basedir) { - init("/{0}", basedir, getClass().getClassLoader()); + this.location = "/{0}"; + this.basedir = basedir; + this.classLoader = getClass().getClassLoader(); } /** @@ -375,7 +386,9 @@ public AssetHandler(final Path basedir) { * @param pattern Pattern to locate static resources. */ public AssetHandler(final String pattern) { - init(Route.normalize(pattern), Paths.get("public"), getClass().getClassLoader()); + this.location = Route.normalize(pattern); + this.basedir = Paths.get("public"); + this.classLoader = getClass().getClassLoader(); } /** @@ -422,6 +435,45 @@ public AssetHandler maxAge(final long maxAge) { return this; } + /** + * Set the route definition and initialize the handler. + * + * @param route Route definition. + * @return This handler. + */ + public AssetHandler setRoute(final Route.AssetDefinition route) { + String prefix; + boolean rootLocation = location.equals("/") || location.equals("/{0}"); + if (rootLocation) { + String pattern = route.pattern(); + int i = pattern.indexOf("/*"); + if (i > 0) { + prefix = pattern.substring(0, i + 1); + } else { + prefix = pattern; + } + } else { + int i = location.indexOf("{"); + if (i > 0) { + prefix = location.substring(0, i); + } else { + /// TODO: review what we have here + prefix = location; + } + } + if (prefix.startsWith("/")) { + prefix = prefix.substring(1); + } + if (prefix.isEmpty() && rootLocation) { + throw new IllegalArgumentException( + "For security reasons root classpath access is not allowed. Map your static resources " + + "using a prefix like: assets(static/**); or use a location classpath prefix like: " + + "assets(/, /static/{0})"); + } + init(prefix, location, basedir, classLoader); + return this; + } + /** * Parse value as {@link Duration}. If the value is already a number then it uses as seconds. * Otherwise, it parse expressions like: 8m, 1h, 365d, etc... @@ -485,7 +537,6 @@ public void handle(final Request req, final Response rsp) throws Throwable { } private void doHandle(final Request req, final Response rsp, final Asset asset) throws Throwable { - // handle etag if (this.etag) { String etag = asset.etag(); @@ -551,12 +602,13 @@ protected URL resolve(final String path) throws Exception { return loader.getResource(path); } - private void init(final String pattern, final Path basedir, final ClassLoader loader) { + private void init(final String classPathPrefix, final String location, final Path basedir, + final ClassLoader loader) { requireNonNull(loader, "Resource loader is required."); - this.fn = pattern.equals("/") + this.fn = location.equals("/") ? (req, p) -> prefix.apply(p) - : (req, p) -> MessageFormat.format(prefix.apply(pattern), vars(req)); - this.loader = loader(basedir, loader); + : (req, p) -> MessageFormat.format(prefix.apply(location), vars(req)); + this.loader = loader(basedir, classpathLoader(classPathPrefix, classLoader)); } private static Object[] vars(final Request req) { @@ -564,8 +616,8 @@ private static Object[] vars(final Request req) { return vars.values().toArray(new Object[vars.size()]); } - private static Loader loader(final Path basedir, final ClassLoader classloader) { - if (Files.exists(basedir)) { + private static Loader loader(final Path basedir, Loader classpath) { + if (basedir != null && Files.exists(basedir)) { return name -> { Path path = basedir.resolve(name).normalize(); if (Files.exists(path) && path.startsWith(basedir)) { @@ -575,10 +627,45 @@ private static Loader loader(final Path basedir, final ClassLoader classloader) // shh } } - return classloader.getResource(name); + return classpath.getResource(name); }; } - return classloader::getResource; + return classpath; + } + + private static Loader classpathLoader(String prefix, ClassLoader classloader) { + return name -> { + String safePath = safePath(name); + if (safePath.startsWith(prefix)) { + URL resource = classloader.getResource(safePath); + return resource; + } + return null; + }; + } + + private static String safePath(String name) { + if (name.indexOf("./") > 0) { + Path path = toPath(name.split("/")).normalize(); + return toStringPath(path); + } + return name; + } + + private static String toStringPath(Path path) { + StringBuilder buffer = new StringBuilder(); + for (Path segment : path) { + buffer.append("/").append(segment); + } + return buffer.substring(1); + } + + private static Path toPath(String[] segments) { + Path path = Paths.get(segments[0]); + for (int i = 1; i < segments.length; i++) { + path = path.resolve(segments[i]); + } + return path; } private static Throwing.Function prefix() { diff --git a/jooby/src/main/java/org/jooby/internal/AssetSource.java b/jooby/src/main/java/org/jooby/internal/AssetSource.java new file mode 100644 index 0000000000..0ec547ca5a --- /dev/null +++ b/jooby/src/main/java/org/jooby/internal/AssetSource.java @@ -0,0 +1,247 @@ +/** + * Apache License + * Version 2.0, January 2004 + * http://www.apache.org/licenses/ + * + * TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + * + * 1. Definitions. + * + * "License" shall mean the terms and conditions for use, reproduction, + * and distribution as defined by Sections 1 through 9 of this document. + * + * "Licensor" shall mean the copyright owner or entity authorized by + * the copyright owner that is granting the License. + * + * "Legal Entity" shall mean the union of the acting entity and all + * other entities that control, are controlled by, or are under common + * control with that entity. For the purposes of this definition, + * "control" means (i) the power, direct or indirect, to cause the + * direction or management of such entity, whether by contract or + * otherwise, or (ii) ownership of fifty percent (50%) or more of the + * outstanding shares, or (iii) beneficial ownership of such entity. + * + * "You" (or "Your") shall mean an individual or Legal Entity + * exercising permissions granted by this License. + * + * "Source" form shall mean the preferred form for making modifications, + * including but not limited to software source code, documentation + * source, and configuration files. + * + * "Object" form shall mean any form resulting from mechanical + * transformation or translation of a Source form, including but + * not limited to compiled object code, generated documentation, + * and conversions to other media types. + * + * "Work" shall mean the work of authorship, whether in Source or + * Object form, made available under the License, as indicated by a + * copyright notice that is included in or attached to the work + * (an example is provided in the Appendix below). + * + * "Derivative Works" shall mean any work, whether in Source or Object + * form, that is based on (or derived from) the Work and for which the + * editorial revisions, annotations, elaborations, or other modifications + * represent, as a whole, an original work of authorship. For the purposes + * of this License, Derivative Works shall not include works that remain + * separable from, or merely link (or bind by name) to the interfaces of, + * the Work and Derivative Works thereof. + * + * "Contribution" shall mean any work of authorship, including + * the original version of the Work and any modifications or additions + * to that Work or Derivative Works thereof, that is intentionally + * submitted to Licensor for inclusion in the Work by the copyright owner + * or by an individual or Legal Entity authorized to submit on behalf of + * the copyright owner. For the purposes of this definition, "submitted" + * means any form of electronic, verbal, or written communication sent + * to the Licensor or its representatives, including but not limited to + * communication on electronic mailing lists, source code control systems, + * and issue tracking systems that are managed by, or on behalf of, the + * Licensor for the purpose of discussing and improving the Work, but + * excluding communication that is conspicuously marked or otherwise + * designated in writing by the copyright owner as "Not a Contribution." + * + * "Contributor" shall mean Licensor and any individual or Legal Entity + * on behalf of whom a Contribution has been received by Licensor and + * subsequently incorporated within the Work. + * + * 2. Grant of Copyright License. Subject to the terms and conditions of + * this License, each Contributor hereby grants to You a perpetual, + * worldwide, non-exclusive, no-charge, royalty-free, irrevocable + * copyright license to reproduce, prepare Derivative Works of, + * publicly display, publicly perform, sublicense, and distribute the + * Work and such Derivative Works in Source or Object form. + * + * 3. Grant of Patent License. Subject to the terms and conditions of + * this License, each Contributor hereby grants to You a perpetual, + * worldwide, non-exclusive, no-charge, royalty-free, irrevocable + * (except as stated in this section) patent license to make, have made, + * use, offer to sell, sell, import, and otherwise transfer the Work, + * where such license applies only to those patent claims licensable + * by such Contributor that are necessarily infringed by their + * Contribution(s) alone or by combination of their Contribution(s) + * with the Work to which such Contribution(s) was submitted. If You + * institute patent litigation against any entity (including a + * cross-claim or counterclaim in a lawsuit) alleging that the Work + * or a Contribution incorporated within the Work constitutes direct + * or contributory patent infringement, then any patent licenses + * granted to You under this License for that Work shall terminate + * as of the date such litigation is filed. + * + * 4. Redistribution. You may reproduce and distribute copies of the + * Work or Derivative Works thereof in any medium, with or without + * modifications, and in Source or Object form, provided that You + * meet the following conditions: + * + * (a) You must give any other recipients of the Work or + * Derivative Works a copy of this License; and + * + * (b) You must cause any modified files to carry prominent notices + * stating that You changed the files; and + * + * (c) You must retain, in the Source form of any Derivative Works + * that You distribute, all copyright, patent, trademark, and + * attribution notices from the Source form of the Work, + * excluding those notices that do not pertain to any part of + * the Derivative Works; and + * + * (d) If the Work includes a "NOTICE" text file as part of its + * distribution, then any Derivative Works that You distribute must + * include a readable copy of the attribution notices contained + * within such NOTICE file, excluding those notices that do not + * pertain to any part of the Derivative Works, in at least one + * of the following places: within a NOTICE text file distributed + * as part of the Derivative Works; within the Source form or + * documentation, if provided along with the Derivative Works; or, + * within a display generated by the Derivative Works, if and + * wherever such third-party notices normally appear. The contents + * of the NOTICE file are for informational purposes only and + * do not modify the License. You may add Your own attribution + * notices within Derivative Works that You distribute, alongside + * or as an addendum to the NOTICE text from the Work, provided + * that such additional attribution notices cannot be construed + * as modifying the License. + * + * You may add Your own copyright statement to Your modifications and + * may provide additional or different license terms and conditions + * for use, reproduction, or distribution of Your modifications, or + * for any such Derivative Works as a whole, provided Your use, + * reproduction, and distribution of the Work otherwise complies with + * the conditions stated in this License. + * + * 5. Submission of Contributions. Unless You explicitly state otherwise, + * any Contribution intentionally submitted for inclusion in the Work + * by You to the Licensor shall be under the terms and conditions of + * this License, without any additional terms or conditions. + * Notwithstanding the above, nothing herein shall supersede or modify + * the terms of any separate license agreement you may have executed + * with Licensor regarding such Contributions. + * + * 6. Trademarks. This License does not grant permission to use the trade + * names, trademarks, service marks, or product names of the Licensor, + * except as required for reasonable and customary use in describing the + * origin of the Work and reproducing the content of the NOTICE file. + * + * 7. Disclaimer of Warranty. Unless required by applicable law or + * agreed to in writing, Licensor provides the Work (and each + * Contributor provides its Contributions) on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied, including, without limitation, any warranties or conditions + * of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + * PARTICULAR PURPOSE. You are solely responsible for determining the + * appropriateness of using or redistributing the Work and assume any + * risks associated with Your exercise of permissions under this License. + * + * 8. Limitation of Liability. In no event and under no legal theory, + * whether in tort (including negligence), contract, or otherwise, + * unless required by applicable law (such as deliberate and grossly + * negligent acts) or agreed to in writing, shall any Contributor be + * liable to You for damages, including any direct, indirect, special, + * incidental, or consequential damages of any character arising as a + * result of this License or out of the use or inability to use the + * Work (including but not limited to damages for loss of goodwill, + * work stoppage, computer failure or malfunction, or any and all + * other commercial damages or losses), even if such Contributor + * has been advised of the possibility of such damages. + * + * 9. Accepting Warranty or Additional Liability. While redistributing + * the Work or Derivative Works thereof, You may choose to offer, + * and charge a fee for, acceptance of support, warranty, indemnity, + * or other liability obligations and/or rights consistent with this + * License. However, in accepting such obligations, You may act only + * on Your own behalf and on Your sole responsibility, not on behalf + * of any other Contributor, and only if You agree to indemnify, + * defend, and hold each Contributor harmless for any liability + * incurred by, or claims asserted against, such Contributor by reason + * of your accepting any such warranty or additional liability. + * + * END OF TERMS AND CONDITIONS + * + * APPENDIX: How to apply the Apache License to your work. + * + * To apply the Apache License to your work, attach the following + * boilerplate notice, with the fields enclosed by brackets "{}" + * replaced with your own identifying information. (Don't include + * the brackets!) The text should be enclosed in the appropriate + * comment syntax for the file format. We also recommend that a + * file or class name and description of purpose be included on the + * same "printed page" as the copyright notice for easier + * identification within third-party archives. + * + * Copyright 2014 Edgar Espina + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jooby.internal; + +import com.google.common.base.Strings; + +import java.net.MalformedURLException; +import java.net.URL; +import java.nio.file.Files; +import java.nio.file.Path; + +public interface AssetSource { + URL getResource(String name); + + static AssetSource fromClassPath(ClassLoader loader, String source) { + if (Strings.isNullOrEmpty(source) || "/".equals(source.trim())) { + throw new IllegalArgumentException( + "For security reasons root classpath access is not allowed: " + source); + } + return path -> { + URL resource = loader.getResource(path); + if (resource == null) { + return null; + } + String realPath = resource.getPath(); + if (realPath.startsWith(source)) { + return resource; + } + return null; + }; + } + + static AssetSource fromFileSystem(Path basedir) { + return name -> { + Path path = basedir.resolve(name).normalize(); + if (Files.exists(path) && path.startsWith(basedir)) { + try { + return path.toUri().toURL(); + } catch (MalformedURLException x) { + // shh + } + } + return null; + }; + } +} diff --git a/jooby/src/main/java/org/jooby/internal/HttpHandlerImpl.java b/jooby/src/main/java/org/jooby/internal/HttpHandlerImpl.java index 62df0a7574..4b3c38bea6 100644 --- a/jooby/src/main/java/org/jooby/internal/HttpHandlerImpl.java +++ b/jooby/src/main/java/org/jooby/internal/HttpHandlerImpl.java @@ -627,7 +627,7 @@ private static Route[] routes(final Set routeDefs, final Strin // default /favicon.ico handler: rsp.status(Status.NOT_FOUND).end(); } else { - throw new Err(Status.NOT_FOUND, req.path(true)); + throw new Err(Status.NOT_FOUND, req.path()); } } }, method, path, "err", accept)); diff --git a/jooby/src/main/java/org/jooby/internal/RequestImpl.java b/jooby/src/main/java/org/jooby/internal/RequestImpl.java index c501b7e15f..52732f946d 100644 --- a/jooby/src/main/java/org/jooby/internal/RequestImpl.java +++ b/jooby/src/main/java/org/jooby/internal/RequestImpl.java @@ -207,19 +207,7 @@ import com.google.inject.Injector; import com.google.inject.Key; import com.typesafe.config.Config; -import static java.util.Objects.requireNonNull; -import org.jooby.Cookie; -import org.jooby.Env; -import org.jooby.Err; -import org.jooby.MediaType; -import org.jooby.Mutant; -import org.jooby.Parser; -import org.jooby.Request; -import org.jooby.Response; -import org.jooby.Route; -import org.jooby.Session; -import org.jooby.Status; -import org.jooby.Upload; +import org.jooby.*; import org.jooby.funzy.Try; import org.jooby.internal.parser.ParserExecutor; import org.jooby.spi.NativeRequest; @@ -228,20 +216,15 @@ import java.io.File; import java.io.IOException; import java.nio.charset.Charset; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Locale; +import java.util.*; import java.util.Locale.LanguageRange; -import java.util.Map; -import java.util.Optional; import java.util.function.BiFunction; import java.util.function.Function; import java.util.function.Supplier; import java.util.stream.Collectors; +import static java.util.Objects.requireNonNull; + public class RequestImpl implements Request { private final Map params = new HashMap<>(); @@ -399,6 +382,13 @@ public List files(final String name) throws IOException { return uploads; } + public List files() throws IOException { + return req.files() + .stream() + .map(upload -> new UploadImpl(injector, upload)) + .collect(Collectors.toList()); + } + private Mutant _param(final String name, final Function xss) { Mutant param = this.params.get(name); if (param == null) { @@ -446,7 +436,7 @@ public Map headers() { public Mutant cookie(final String name) { List values = req.cookies().stream().filter(c -> c.name().equalsIgnoreCase(name)) .findFirst() - .map(cookie -> ImmutableList.of(cookie.value().get())) + .map(cookie -> ImmutableList.of(cookie.value().orElse(""))) .orElse(ImmutableList.of()); return new MutantImpl(require(ParserExecutor.class), @@ -469,8 +459,7 @@ public Mutant body() throws Exception { Integer.toHexString(System.identityHashCode(this))); files.add(fbody); int bufferSize = conf.getBytes("server.http.RequestBufferSize").intValue(); - Parser.BodyReference body = new BodyReferenceImpl(length, charset(), fbody, req.in(), - bufferSize); + Parser.BodyReference body = new BodyReferenceImpl(length, charset(), fbody, req.in(), bufferSize); return new MutantImpl(require(ParserExecutor.class), type, body); } return new MutantImpl(require(ParserExecutor.class), type, new EmptyBodyReference()); @@ -670,5 +659,4 @@ private Session setSession(final SessionManager sm, final Response rsp, final Se private void destroySession() { this.reqSession = Optional.empty(); } - } diff --git a/jooby/src/main/java/org/jooby/internal/ResponseImpl.java b/jooby/src/main/java/org/jooby/internal/ResponseImpl.java index 503f5365be..57b8718566 100644 --- a/jooby/src/main/java/org/jooby/internal/ResponseImpl.java +++ b/jooby/src/main/java/org/jooby/internal/ResponseImpl.java @@ -280,6 +280,8 @@ public class ResponseImpl implements Response { private Optional byteRange; + private boolean resetHeadersOnError = true; + public ResponseImpl(final RequestImpl req, final ParserExecutor parserExecutor, final NativeResponse rsp, final Route route, final List renderers, final Map rendererMap, final Map locals, @@ -296,6 +298,14 @@ public ResponseImpl(final RequestImpl req, final ParserExecutor parserExecutor, this.byteRange = byteRange; } + @Override public boolean isResetHeadersOnError() { + return resetHeadersOnError; + } + + @Override public void setResetHeadersOnError(boolean resetHeadersOnError) { + this.resetHeadersOnError = resetHeadersOnError; + } + @Override public void download(final String filename, final InputStream stream) throws Throwable { requireNonNull(filename, "A file's name is required."); @@ -585,9 +595,11 @@ private void writeCookies() { } public void reset() { - status = null; - this.cookies.clear(); - rsp.reset(); + if (resetHeadersOnError) { + status = null; + this.cookies.clear(); + rsp.reset(); + } } void route(final Route route) { diff --git a/jooby/src/main/java/org/jooby/internal/RouteImpl.java b/jooby/src/main/java/org/jooby/internal/RouteImpl.java index 253ec4fa49..3d12d6dbc9 100644 --- a/jooby/src/main/java/org/jooby/internal/RouteImpl.java +++ b/jooby/src/main/java/org/jooby/internal/RouteImpl.java @@ -233,7 +233,7 @@ public class RouteImpl implements RouteWithFilter { public static RouteWithFilter notFound(final String method, final String path) { return new FallbackRoute("404", method, path, MediaType.ALL, (req, rsp, chain) -> { if (!rsp.status().isPresent()) { - throw new Err(Status.NOT_FOUND, req.path(true)); + throw new Err(Status.NOT_FOUND, req.path()); } }); } diff --git a/jooby/src/main/java/org/jooby/internal/RouteMetadata.java b/jooby/src/main/java/org/jooby/internal/RouteMetadata.java index bfbd0a475b..2f95efd40f 100644 --- a/jooby/src/main/java/org/jooby/internal/RouteMetadata.java +++ b/jooby/src/main/java/org/jooby/internal/RouteMetadata.java @@ -289,7 +289,7 @@ private static String classfile(final Class owner) { } private static ClassVisitor visitor(final Map md) { - return new ClassVisitor(Opcodes.ASM5) { + return new ClassVisitor(Opcodes.ASM7) { @Override public MethodVisitor visitMethod(final int access, final String name, @@ -308,7 +308,7 @@ public MethodVisitor visitMethod(final int access, final String name, int minIdx = ((access & Opcodes.ACC_STATIC) > 0) ? 0 : 1; int maxIdx = Arrays.stream(args).mapToInt(Type::getSize).sum(); - return new MethodVisitor(Opcodes.ASM5) { + return new MethodVisitor(Opcodes.ASM7) { private int i = 0; diff --git a/jooby/src/main/java/org/jooby/internal/RoutePattern.java b/jooby/src/main/java/org/jooby/internal/RoutePattern.java index 5535fd8c4a..4c55fa39d5 100644 --- a/jooby/src/main/java/org/jooby/internal/RoutePattern.java +++ b/jooby/src/main/java/org/jooby/internal/RoutePattern.java @@ -387,7 +387,7 @@ private static Function fn(final RoutePattern owner, final @Override public RouteMatcher apply(final String fullpath) { - String path = fullpath.substring(fullpath.indexOf('/')); + String path = fullpath.substring(Math.max(0, fullpath.indexOf('/'))); if (complex) { return new RegexRouteMatcher(path, regex.matcher(fullpath), vars); } diff --git a/jooby/src/main/java/org/jooby/internal/WebSocketImpl.java b/jooby/src/main/java/org/jooby/internal/WebSocketImpl.java index 8871c0590a..33706629c5 100644 --- a/jooby/src/main/java/org/jooby/internal/WebSocketImpl.java +++ b/jooby/src/main/java/org/jooby/internal/WebSocketImpl.java @@ -206,7 +206,9 @@ import com.google.common.collect.ImmutableList; import com.google.inject.Injector; import com.google.inject.Key; + import static java.util.Objects.requireNonNull; + import org.jooby.Err; import org.jooby.MediaType; import org.jooby.Mutant; @@ -307,7 +309,9 @@ public void close(final CloseStatus status) { removeSession(this); synchronized (this) { open = false; - ws.close(status.code(), status.reason()); + if (ws != null) { + ws.close(status.code(), status.reason()); + } } } diff --git a/jooby/src/main/java/org/jooby/spi/NativeRequest.java b/jooby/src/main/java/org/jooby/spi/NativeRequest.java index d1e8d36ede..4fdc7b523b 100644 --- a/jooby/src/main/java/org/jooby/spi/NativeRequest.java +++ b/jooby/src/main/java/org/jooby/spi/NativeRequest.java @@ -300,6 +300,14 @@ default Map attributes() { */ List files(String name) throws IOException; + /** + * Get all the files or an empty list. + * + * @return All the files or an empty list. + * @throws IOException If file parsing fails. + */ + List files() throws IOException; + /** * Input stream that represent the body. * diff --git a/modules/jooby-filewatcher/src/main/java/org/jooby/filewatcher/WatchEventModifier.java b/jooby/src/main/java/org/jooby/spi/WatchEventModifier.java similarity index 95% rename from modules/jooby-filewatcher/src/main/java/org/jooby/filewatcher/WatchEventModifier.java rename to jooby/src/main/java/org/jooby/spi/WatchEventModifier.java index 1973d5197f..6104f302bf 100644 --- a/modules/jooby-filewatcher/src/main/java/org/jooby/filewatcher/WatchEventModifier.java +++ b/jooby/src/main/java/org/jooby/spi/WatchEventModifier.java @@ -201,25 +201,22 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.jooby.filewatcher; +package org.jooby.spi; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; import java.nio.file.WatchEvent; -class WatchEventModifier implements WatchEvent.Modifier { +public class WatchEventModifier { - private final String name; - - public WatchEventModifier(final String name) { - this.name = name.toUpperCase(); - } - - @Override - public String name() { - return name; - } - - @Override - public String toString() { - return name; + public static WatchEvent.Modifier modifier(String name) { + try { + Class e = WatchEventModifier.class.getClassLoader() + .loadClass("com.sun.nio.file.SensitivityWatchEventModifier"); + Method m = e.getDeclaredMethod("valueOf", String.class); + return (WatchEvent.Modifier) m.invoke(null, name); + } catch (ClassNotFoundException | NoSuchMethodException | IllegalAccessException | InvocationTargetException x) { + return () -> name; + } } } diff --git a/jooby/src/main/resources/org/jooby/jooby.conf b/jooby/src/main/resources/org/jooby/jooby.conf index 6b9a869c8e..c9af91db25 100644 --- a/jooby/src/main/resources/org/jooby/jooby.conf +++ b/jooby/src/main/resources/org/jooby/jooby.conf @@ -16,7 +16,7 @@ application { # class = App.class.getName() # tmpdir - tmpdir = ${java.io.tmpdir}/${application.name} + tmpdir = ${java.io.tmpdir}${file.separator}${application.name} # path (a.k.a. as contextPath) path = / @@ -151,10 +151,10 @@ server { ws { # The maximum size of a text message. - MaxTextMessageSize = 16k + MaxTextMessageSize = 131072 # The maximum size of a binary message. - MaxBinaryMessageSize = 16k + MaxBinaryMessageSize = 131072 # The time in ms (milliseconds) that a websocket may be idle before closing. IdleTimeout = 5minutes diff --git a/jooby/src/test/java/org/jooby/DefaultErrHandlerTest.java b/jooby/src/test/java/org/jooby/DefaultErrHandlerTest.java index 8eebcb3b75..18649551e5 100644 --- a/jooby/src/test/java/org/jooby/DefaultErrHandlerTest.java +++ b/jooby/src/test/java/org/jooby/DefaultErrHandlerTest.java @@ -1,6 +1,8 @@ package org.jooby; import com.google.common.collect.ImmutableList; +import com.google.common.escape.Escapers; +import com.google.common.html.HtmlEscapers; import com.typesafe.config.Config; import static org.easymock.EasyMock.expect; import org.jooby.test.MockUnit; @@ -15,6 +17,7 @@ import java.io.PrintWriter; import java.io.StringWriter; +import java.util.LinkedHashMap; import java.util.Map; @RunWith(PowerMockRunner.class) @@ -66,6 +69,7 @@ private MockUnit.Block handleErr(Throwable ex, boolean stacktrace) { expect(conf.getBoolean("err.stacktrace")).andReturn(stacktrace); Env env = unit.get(Env.class); expect(env.name()).andReturn("dev"); + expect(env.xss("html")).andReturn(HtmlEscapers.htmlEscaper()::escape); Request req = unit.get(Request.class); @@ -112,13 +116,45 @@ public void handleWithErrMessage() throws Exception { }); } + @SuppressWarnings({"unchecked"}) + @Test + public void handleWithHtmlErrMessage() throws Exception { + Err ex = new Err(500, "Something something dark"); + + StringWriter writer = new StringWriter(); + ex.printStackTrace(new PrintWriter(writer)); + String[] stacktrace = writer.toString().replace("\r", "").split("\\n"); + + new MockUnit(Request.class, Response.class, Route.class, Env.class, Config.class) + .expect(handleErr(ex, true)) + .run(unit -> { + + Request req = unit.get(Request.class); + Response rsp = unit.get(Response.class); + + new Err.DefHandler().handle(req, rsp, ex); + }, + unit -> { + Result result = unit.captured(Result.class).iterator().next(); + View view = (View) result.ifGet(ImmutableList.of(MediaType.html)).get(); + assertEquals("err", view.name()); + checkErr(stacktrace, "Server Error(500): Something something <em>dark</em>", + (Map) view.model() + .get("err")); + + Object hash = result.ifGet(MediaType.ALL).get(); + assertEquals(4, ((Map) hash).size()); + }); + } + private void checkErr(final String[] stacktrace, final String message, final Map err) { - assertEquals(message, err.remove("message")); - assertEquals("Server Error", err.remove("reason")); - assertEquals(500, err.remove("status")); - assertArrayEquals(stacktrace, (String[]) err.remove("stacktrace")); - assertEquals(err.toString(), 0, err.size()); + final Map copy = new LinkedHashMap<>(err); + assertEquals(message, copy.remove("message")); + assertEquals("Server Error", copy.remove("reason")); + assertEquals(500, copy.remove("status")); + assertArrayEquals(stacktrace, (String[]) copy.remove("stacktrace")); + assertEquals(copy.toString(), 0, copy.size()); } } diff --git a/jooby/src/test/java/org/jooby/RequestTest.java b/jooby/src/test/java/org/jooby/RequestTest.java index f8493197bb..81d53d892b 100644 --- a/jooby/src/test/java/org/jooby/RequestTest.java +++ b/jooby/src/test/java/org/jooby/RequestTest.java @@ -22,6 +22,8 @@ import com.google.inject.Key; import com.google.inject.TypeLiteral; +import javax.annotation.Nonnull; + public class RequestTest { public class RequestMock implements Request { @@ -241,6 +243,11 @@ public List files(final String name) throws IOException { throw new UnsupportedOperationException(); } + @Nonnull + @Override + public List files() throws IOException { + throw new UnsupportedOperationException(); + } } @Test diff --git a/jooby/src/test/java/org/jooby/ResponseTest.java b/jooby/src/test/java/org/jooby/ResponseTest.java index 4a79aae0d8..78cbc24717 100644 --- a/jooby/src/test/java/org/jooby/ResponseTest.java +++ b/jooby/src/test/java/org/jooby/ResponseTest.java @@ -17,6 +17,14 @@ public class ResponseTest { public static class ResponseMock implements Response { + @Override public boolean isResetHeadersOnError() { + throw new UnsupportedOperationException(); + } + + @Override public void setResetHeadersOnError(boolean value) { + throw new UnsupportedOperationException(); + } + @Override public void download(final String filename, final InputStream stream) throws Exception { throw new UnsupportedOperationException(); diff --git a/jooby/src/test/java/org/jooby/handlers/AssetHandlerTest.java b/jooby/src/test/java/org/jooby/handlers/AssetHandlerTest.java index 35343529d1..afe4e0c4c1 100644 --- a/jooby/src/test/java/org/jooby/handlers/AssetHandlerTest.java +++ b/jooby/src/test/java/org/jooby/handlers/AssetHandlerTest.java @@ -1,7 +1,12 @@ package org.jooby.handlers; -import static org.easymock.EasyMock.expect; -import static org.junit.Assert.assertNotNull; +import org.jooby.Route; +import org.jooby.test.MockUnit; +import org.jooby.test.MockUnit.Block; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; import java.io.File; import java.net.MalformedURLException; @@ -11,15 +16,11 @@ import java.nio.file.Path; import java.nio.file.Paths; -import org.jooby.test.MockUnit; -import org.jooby.test.MockUnit.Block; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.powermock.core.classloader.annotations.PrepareForTest; -import org.powermock.modules.junit4.PowerMockRunner; +import static org.easymock.EasyMock.expect; +import static org.junit.Assert.assertNotNull; @RunWith(PowerMockRunner.class) -@PrepareForTest({AssetHandler.class, File.class, Paths.class, Files.class }) +@PrepareForTest({AssetHandler.class, File.class, Paths.class, Files.class}) public class AssetHandlerTest { @Test @@ -28,24 +29,30 @@ public void customClassloader() throws Exception { new MockUnit(ClassLoader.class) .expect(publicDir(uri, "JoobyTest.js")) .run(unit -> { - URL value = new AssetHandler("/", unit.get(ClassLoader.class)) + URL value = newHandler(unit, "/") .resolve("JoobyTest.js"); assertNotNull(value); }); } + private AssetHandler newHandler(MockUnit unit, String location) { + AssetHandler handler = new AssetHandler(location, unit.get(ClassLoader.class)); + new Route.AssetDefinition("GET", "/assets/**", handler, false); + return handler; + } + @Test public void shouldCallParentOnMissing() throws Exception { URI uri = Paths.get("src", "test", "resources", "org", "jooby").toUri(); new MockUnit(ClassLoader.class) - .expect(publicDir(uri, "index.js", false)) + .expect(publicDir(uri, "assets/index.js", false)) .expect(unit -> { ClassLoader loader = unit.get(ClassLoader.class); - expect(loader.getResource("index.js")).andReturn(uri.toURL()); + expect(loader.getResource("assets/index.js")).andReturn(uri.toURL()); }) .run(unit -> { - URL value = new AssetHandler("/", unit.get(ClassLoader.class)) - .resolve("index.js"); + URL value = newHandler(unit, "/") + .resolve("assets/index.js"); assertNotNull(value); }); } @@ -54,18 +61,18 @@ public void shouldCallParentOnMissing() throws Exception { public void ignoreMalformedURL() throws Exception { Path path = Paths.get("src", "test", "resources", "org", "jooby"); new MockUnit(ClassLoader.class, URI.class) - .expect(publicDir(null, "index.js")) + .expect(publicDir(null, "assets/index.js")) .expect(unit -> { URI uri = unit.get(URI.class); expect(uri.toURL()).andThrow(new MalformedURLException()); }) .expect(unit -> { ClassLoader loader = unit.get(ClassLoader.class); - expect(loader.getResource("index.js")).andReturn(path.toUri().toURL()); + expect(loader.getResource("assets/index.js")).andReturn(path.toUri().toURL()); }) .run(unit -> { - URL value = new AssetHandler("/", unit.get(ClassLoader.class)) - .resolve("index.js"); + URL value = newHandler(unit, "/") + .resolve("assets/index.js"); assertNotNull(value); }); } diff --git a/jooby/src/test/java/org/jooby/internal/RouteImplTest.java b/jooby/src/test/java/org/jooby/internal/RouteImplTest.java index ff42c9dd9f..ff1c1dbacf 100644 --- a/jooby/src/test/java/org/jooby/internal/RouteImplTest.java +++ b/jooby/src/test/java/org/jooby/internal/RouteImplTest.java @@ -25,7 +25,7 @@ public void notFound() throws Exception { expect(rsp.status()).andReturn(Optional.empty()); Request req = unit.get(Request.class); - expect(req.path(true)).andReturn("/x"); + expect(req.path()).andReturn("/x"); }) .run(unit -> { RouteImpl.notFound("GET", "/x") diff --git a/jooby/src/test/java/org/jooby/internal/RoutePatternTest.java b/jooby/src/test/java/org/jooby/internal/RoutePatternTest.java index 4533edde1c..b9fc79bc50 100644 --- a/jooby/src/test/java/org/jooby/internal/RoutePatternTest.java +++ b/jooby/src/test/java/org/jooby/internal/RoutePatternTest.java @@ -457,4 +457,9 @@ public void ignoreCase() { .matches("GET/Path1"); } + @Test + public void shouldNotBreakOnMissing () { + new RoutePathAssert("GET", "/") + .butNot("GET(X11;"); + } } diff --git a/jooby/src/test/java/org/jooby/test/JoobyRunner.java b/jooby/src/test/java/org/jooby/test/JoobyRunner.java index bf0923bb73..5990e53e59 100644 --- a/jooby/src/test/java/org/jooby/test/JoobyRunner.java +++ b/jooby/src/test/java/org/jooby/test/JoobyRunner.java @@ -105,6 +105,7 @@ private void prepare(final Class klass, final Class server) throws Initial } app = (Jooby) appClass.newInstance(); + app.throwBootstrapException(); if (app instanceof ServerFeature) { int appport = ((ServerFeature) app).port; if (appport > 0) { diff --git a/jooby/src/test/java/org/jooby/test/MockUnit.java b/jooby/src/test/java/org/jooby/test/MockUnit.java index 29e5935f60..573e0c5e1b 100644 --- a/jooby/src/test/java/org/jooby/test/MockUnit.java +++ b/jooby/src/test/java/org/jooby/test/MockUnit.java @@ -209,6 +209,10 @@ public MockUnit expect(final Block block) { return this; } + public MockUnit run(final Block block) throws Exception { + return run(new Block[] {block}); + } + public MockUnit run(final Block... blocks) throws Exception { for (Block block : this.blocks) { diff --git a/modules/coverage-report/pom.xml b/modules/coverage-report/pom.xml index f1bdfc512e..a29169cebe 100644 --- a/modules/coverage-report/pom.xml +++ b/modules/coverage-report/pom.xml @@ -5,7 +5,7 @@ org.jooby modules - 1.5.1-SNAPSHOT + 1.6.9 4.0.0 @@ -82,7 +82,6 @@ ${project.parent.basedir}/jooby-mongodb-rx/src/main/java ${project.parent.basedir}/jooby-couchbase/src/main/java ${project.parent.basedir}/jooby-cassandra/src/main/java - ${project.parent.basedir}/jooby-scanner/src/main/java ${project.parent.basedir}/jooby-csl/src/main/java ${project.parent.basedir}/jooby-unbescape/src/main/java ${project.parent.basedir}/jooby-thymeleaf/src/main/java @@ -149,7 +148,6 @@ ${project.parent.basedir}/jooby-mongodb-rx/src/test/java ${project.parent.basedir}/jooby-couchbase/src/test/java ${project.parent.basedir}/jooby-cassandra/src/test/java - ${project.parent.basedir}/jooby-scanner/src/test/java ${project.parent.basedir}/jooby-csl/src/test/java ${project.parent.basedir}/jooby-unbescape/src/test/java ${project.parent.basedir}/jooby-thymeleaf/src/test/java @@ -709,6 +707,66 @@ 8.1.12.v20180117 + + jdk-1.8.0_181 + + + java.version + 1.8.0_181 + + + + 8.1.12.v20180117 + + + + jdk-1.8.0_191 + + + java.version + 1.8.0_191 + + + + 8.1.13.v20181017 + + + + jdk-1.8.0_192 + + + java.version + 1.8.0_192 + + + + 8.1.13.v20181017 + + + + jdk-1.8.0_201 + + + java.version + 1.8.0_201 + + + + 8.1.13.v20181017 + + + + jdk-1.8.0_202 + + + java.version + 1.8.0_202 + + + + 8.1.13.v20181017 + + @@ -877,12 +935,6 @@ ${project.version} - - org.jooby - jooby-scanner - ${project.version} - - org.jooby jooby-csl @@ -1116,6 +1168,12 @@ org.jooby jooby-netty ${project.version} + + + io.netty + netty-tcnative-boringssl-static + + diff --git a/modules/coverage-report/src/test/java/org/jooby/elasticsearch/ElasticsearchClientAPIFeature.java b/modules/coverage-report/src/test/java/org/jooby/elasticsearch/ElasticsearchClientAPIFeature.java index 9e8cdd03b0..45e56afcaa 100644 --- a/modules/coverage-report/src/test/java/org/jooby/elasticsearch/ElasticsearchClientAPIFeature.java +++ b/modules/coverage-report/src/test/java/org/jooby/elasticsearch/ElasticsearchClientAPIFeature.java @@ -1,6 +1,7 @@ package org.jooby.elasticsearch; import org.elasticsearch.client.RestClient; +import org.elasticsearch.client.RestHighLevelClient; import org.jooby.test.ServerFeature; import org.junit.Test; @@ -11,6 +12,7 @@ public class ElasticsearchClientAPIFeature extends ServerFeature { use(new Elasticsearch()); get("/", req -> req.require(RestClient.class).getClass().getName()); + get("/hlrc", req -> req.require(RestHighLevelClient.class).getClass().getName()); } @@ -19,6 +21,9 @@ public void boot() throws Exception { request() .get("/") .expect("org.elasticsearch.client.RestClient"); + request() + .get("/hlrc") + .expect("org.elasticsearch.client.RestHighLevelClient"); } } diff --git a/modules/coverage-report/src/test/java/org/jooby/issues/Issue1299.java b/modules/coverage-report/src/test/java/org/jooby/issues/Issue1299.java new file mode 100644 index 0000000000..a3ac7abf73 --- /dev/null +++ b/modules/coverage-report/src/test/java/org/jooby/issues/Issue1299.java @@ -0,0 +1,32 @@ +package org.jooby.issues; + +import org.jooby.test.ServerFeature; +import org.junit.Test; + +public class Issue1299 extends ServerFeature { + + { + use("*", (req, rsp) -> { + if (req.param("noreset").booleanValue(false)) { + rsp.setResetHeadersOnError(false); + } + }); + get("/1299", req -> { + req.flash("error", "error"); + return req.param("missing").value(); + }); + + err((req, rsp, x) -> { + rsp.status(200).end(); + }); + } + + @Test + public void shouldNotResetHeaders() throws Exception { + request() + .get("/1299") + .expect(200) + .header("Set-Cookie", (String) null); + } + +} diff --git a/modules/coverage-report/src/test/java/org/jooby/issues/Issue1331.java b/modules/coverage-report/src/test/java/org/jooby/issues/Issue1331.java new file mode 100644 index 0000000000..9d447ae4c3 --- /dev/null +++ b/modules/coverage-report/src/test/java/org/jooby/issues/Issue1331.java @@ -0,0 +1,25 @@ +package org.jooby.issues; + +import org.jooby.test.ServerFeature; +import org.junit.Test; + +public class Issue1331 extends ServerFeature { + + { + get("/1331", req -> { + return req.cookie("login").value("not set"); + }); + } + + @Test + public void shouldNotFailOnEmptyCookies() throws Exception { + request() + .get("/1331") + .header("Cookie", "login=;Version=1;Path=/1331") + .expect(""); + request() + .get("/1331") + .expect("not set"); + } + +} diff --git a/modules/coverage-report/src/test/java/org/jooby/issues/Issue1639.java b/modules/coverage-report/src/test/java/org/jooby/issues/Issue1639.java new file mode 100644 index 0000000000..12cd2b874b --- /dev/null +++ b/modules/coverage-report/src/test/java/org/jooby/issues/Issue1639.java @@ -0,0 +1,31 @@ +package org.jooby.issues; + +import org.jooby.test.ServerFeature; +import org.junit.Test; + +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; + +import static org.junit.Assert.assertTrue; + +public class Issue1639 extends ServerFeature { + + { + Path dir = Paths.get(System.getProperty("user.dir"), "src", "test", "resources", "assets"); + assertTrue(Files.exists(dir)); + assets("/static/**", dir); + } + + @Test + public void shouldNotFallbackToArbitraryClasspathResources() throws Exception { + request() + .get("/static/WEB-INF/web2.xml") + .expect(404); + + request() + .get("/static/../WEB-INF/web2.xml") + .expect(404); + } + +} diff --git a/modules/coverage-report/src/test/java/org/jooby/issues/Issue1639b.java b/modules/coverage-report/src/test/java/org/jooby/issues/Issue1639b.java new file mode 100644 index 0000000000..424a60c64f --- /dev/null +++ b/modules/coverage-report/src/test/java/org/jooby/issues/Issue1639b.java @@ -0,0 +1,33 @@ +package org.jooby.issues; + +import org.jooby.test.ServerFeature; +import org.junit.Test; + +import java.nio.file.Paths; + +public class Issue1639b extends ServerFeature { + + { + assets("/static/**/*.js", Paths.get("static")); + } + + @Test + public void shouldNotByPassPrefixValue() throws Exception { + request() + .get("/static/org/jooby/issues/Issue1639b.class.js") + .expect(404); + + request() + .get("/static/../org/jooby/issues/Issue1639b.class.js") + .expect(404); + + request() + .get("/static/..%252forg/jooby/issues/Issue1639b.class.js") + .expect(404); + + request() + .get("/static/org/jooby/issues/Issue1639b.class") + .expect(404); + } + +} diff --git a/modules/coverage-report/src/test/java/org/jooby/issues/Issue1639c.java b/modules/coverage-report/src/test/java/org/jooby/issues/Issue1639c.java new file mode 100644 index 0000000000..33e73a2051 --- /dev/null +++ b/modules/coverage-report/src/test/java/org/jooby/issues/Issue1639c.java @@ -0,0 +1,24 @@ +package org.jooby.issues; + +import org.jooby.test.ServerFeature; +import org.junit.Test; + +import java.nio.file.Paths; + +public class Issue1639c extends ServerFeature { + + { + assets("/static/**"); + } + + @Test + public void shouldNotByPassPrefixValue() throws Exception { + request() + .get("/static/..%252forg/jooby/issues/Issue1639c.class") + .expect(404); + request() + .get("/static/../org/jooby/issues/Issue1639c.class") + .expect(404); + } + +} diff --git a/modules/coverage-report/src/test/java/org/jooby/issues/Issue418.java b/modules/coverage-report/src/test/java/org/jooby/issues/Issue418.java index 5ad5bfa998..72edc84e97 100644 --- a/modules/coverage-report/src/test/java/org/jooby/issues/Issue418.java +++ b/modules/coverage-report/src/test/java/org/jooby/issues/Issue418.java @@ -26,9 +26,11 @@ import org.jooby.MediaType; import org.jooby.Results; import org.jooby.test.ServerFeature; + import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; + import org.junit.Test; import java.io.IOException; @@ -45,6 +47,7 @@ import java.util.concurrent.Phaser; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicReference; +import java.util.function.UnaryOperator; public class Issue418 extends ServerFeature { @@ -224,7 +227,7 @@ public void http1_1_Upgrade() throws Throwable { } } - assertTrue(upgrade.toString().startsWith("HTTP/1.1 101 ")); + assertTrue(upgrade.toString(), upgrade.toString().startsWith("HTTP/1.1 101 ")); MappedByteBufferPool byteBufferPool = new MappedByteBufferPool(); new Generator(byteBufferPool); @@ -232,7 +235,7 @@ public void http1_1_Upgrade() throws Throwable { final AtomicReference headersRef = new AtomicReference<>(); final AtomicReference dataRef = new AtomicReference<>(); final AtomicReference latchRef = new AtomicReference<>(new CountDownLatch(2)); - Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter() { + Parser.Listener.Adapter listener = new Parser.Listener.Adapter() { @Override public void onHeaders(final HeadersFrame frame) { headersRef.set(frame); @@ -244,11 +247,14 @@ public void onData(final DataFrame frame) { dataRef.set(frame); latchRef.get().countDown(); } - }, 4096, 8192); + }; + Parser parser = new Parser(byteBufferPool, listener, 4096, 8192); + parser.init(UnaryOperator.identity()); parseResponse(client, parser); assertTrue(latchRef.get().await(5, TimeUnit.SECONDS)); + // latchRef.get().await(); HeadersFrame response = headersRef.get(); assertNotNull(response); diff --git a/modules/coverage-report/src/test/java/org/jooby/issues/Issue930.java b/modules/coverage-report/src/test/java/org/jooby/issues/Issue930.java new file mode 100644 index 0000000000..abe2f362d5 --- /dev/null +++ b/modules/coverage-report/src/test/java/org/jooby/issues/Issue930.java @@ -0,0 +1,30 @@ +package org.jooby.issues; + +import com.typesafe.config.ConfigFactory; +import com.typesafe.config.ConfigValueFactory; +import org.jooby.json.Gzon; +import org.jooby.json.Jackson; +import org.jooby.test.ServerFeature; +import org.junit.Test; + +public class Issue930 extends ServerFeature { + + { + use(ConfigFactory.empty().withValue("application.env", ConfigValueFactory.fromAnyRef("prod"))); + use(new Gzon()); + } + + @Test + public void gzonRenderJsonWithWideAcceptIsPresent() throws Exception { + request() + .get("/930") + .header("Accept", "application/json, */*") + .expect("{\"message\":\"Not Found(404): /930\",\"status\":404,\"reason\":\"Not Found\"}"); + + request() + .get("/930") + .header("Accept", "application/json") + .expect("{\"message\":\"Not Found(404): /930\",\"status\":404,\"reason\":\"Not Found\"}"); + } + +} diff --git a/modules/coverage-report/src/test/java/org/jooby/jackson/JsonCustomMapperFeature.java b/modules/coverage-report/src/test/java/org/jooby/jackson/JsonCustomMapperFeature.java index fdb10d076b..bfe6a97b49 100644 --- a/modules/coverage-report/src/test/java/org/jooby/jackson/JsonCustomMapperFeature.java +++ b/modules/coverage-report/src/test/java/org/jooby/jackson/JsonCustomMapperFeature.java @@ -1,5 +1,6 @@ package org.jooby.jackson; +import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertSame; import java.net.URISyntaxException; @@ -31,12 +32,12 @@ public class JsonCustomMapperFeature extends ServerFeature { @Test public void get() throws URISyntaxException, Exception { - request() - .get("/members") - .expect("[ {\n" + - " \"id\" : 1,\n" + - " \"name\" : \"pablo\"\n" + - "} ]"); + request().get("/members").expect(value -> + assertEquals("[ {\n" + + " \"id\" : 1,\n" + + " \"name\" : \"pablo\"\n" + + "} ]", value.replaceAll("\r\n", "\n")) + ); } } diff --git a/modules/coverage-report/src/test/java/org/jooby/jackson/JsonDoWithFeature.java b/modules/coverage-report/src/test/java/org/jooby/jackson/JsonDoWithFeature.java index 5731fb1ec9..dabfe83c95 100644 --- a/modules/coverage-report/src/test/java/org/jooby/jackson/JsonDoWithFeature.java +++ b/modules/coverage-report/src/test/java/org/jooby/jackson/JsonDoWithFeature.java @@ -10,6 +10,8 @@ import com.google.common.collect.ImmutableMap; import com.google.common.collect.Lists; +import static org.junit.Assert.assertEquals; + @SuppressWarnings("unchecked") public class JsonDoWithFeature extends ServerFeature { @@ -26,12 +28,12 @@ public class JsonDoWithFeature extends ServerFeature { @Test public void get() throws URISyntaxException, Exception { - request() - .get("/members") - .expect("[ {\n" + - " \"id\" : 1,\n" + - " \"name\" : \"pablo\"\n" + - "} ]"); + request().get("/members").expect(value -> + assertEquals("[ {\n" + + " \"id\" : 1,\n" + + " \"name\" : \"pablo\"\n" + + "} ]", value.replaceAll("\r\n", "\n")) + ); } } diff --git a/modules/coverage-report/src/test/java/org/jooby/whoops/WhoopsTest.java b/modules/coverage-report/src/test/java/org/jooby/whoops/WhoopsTest.java index a63507ea53..85cfe33db6 100644 --- a/modules/coverage-report/src/test/java/org/jooby/whoops/WhoopsTest.java +++ b/modules/coverage-report/src/test/java/org/jooby/whoops/WhoopsTest.java @@ -47,7 +47,7 @@ public void shouldIgnoreMissingClass() { @Test public void locationOf() { - assertTrue(new File(Whoops.locationOf(Whoops.class)).exists()); + assertTrue(Whoops.locationOf(Whoops.class) + " file does not exist", new File(Whoops.locationOf(Whoops.class)).exists()); assertEquals("rt.jar", Whoops.locationOf(Object.class)); } diff --git a/modules/coverage-report/src/test/resources/WEB-INF/web2.xml b/modules/coverage-report/src/test/resources/WEB-INF/web2.xml new file mode 100644 index 0000000000..262735fa3b --- /dev/null +++ b/modules/coverage-report/src/test/resources/WEB-INF/web2.xml @@ -0,0 +1,8 @@ + + + diff --git a/modules/coverage-report/src/test/resources/assets.conf b/modules/coverage-report/src/test/resources/assets.conf new file mode 100644 index 0000000000..e69de29bb2 diff --git a/modules/jooby-akka/README.md b/modules/jooby-akka/README.md index 37c87939f5..bd6408137d 100644 --- a/modules/jooby-akka/README.md +++ b/modules/jooby-akka/README.md @@ -1,5 +1,5 @@ -[![Maven Central](https://maven-badges.herokuapp.com/maven-central/org.jooby/jooby-akka/badge.svg)](https://maven-badges.herokuapp.com/maven-central/org.jooby/jooby-akka) -[![javadoc](https://javadoc.io/badge/org.jooby/jooby-akka.svg)](https://javadoc.io/doc/org.jooby/jooby-akka/1.5.0) +[![Maven](https://img.shields.io/maven-metadata/v/http/central.maven.org/maven2/org/jooby/jooby-akka/maven-metadata.xml.svg)](http://mvnrepository.com/artifact/org.jooby/jooby-akka/1.6.6) +[![javadoc](https://javadoc.io/badge/org.jooby/jooby-akka.svg)](https://javadoc.io/doc/org.jooby/jooby-akka/1.6.6) [![jooby-akka website](https://img.shields.io/badge/jooby-akka-brightgreen.svg)](http://jooby.org/doc/akka) # akka @@ -15,7 +15,7 @@ Small module to build concurrent & distributed applications via [Akka](http://ak org.jooby jooby-akka - 1.5.0 + 1.6.6 ``` diff --git a/modules/jooby-akka/pom.xml b/modules/jooby-akka/pom.xml index 87dac7660f..384cca7eb8 100644 --- a/modules/jooby-akka/pom.xml +++ b/modules/jooby-akka/pom.xml @@ -5,7 +5,7 @@ org.jooby modules - 1.5.1-SNAPSHOT + 1.6.9 4.0.0 diff --git a/modules/jooby-apitool/README.md b/modules/jooby-apitool/README.md index 4e8fd6c06a..d5e3486d16 100644 --- a/modules/jooby-apitool/README.md +++ b/modules/jooby-apitool/README.md @@ -1,5 +1,5 @@ -[![Maven Central](https://maven-badges.herokuapp.com/maven-central/org.jooby/jooby-apitool/badge.svg)](https://maven-badges.herokuapp.com/maven-central/org.jooby/jooby-apitool) -[![javadoc](https://javadoc.io/badge/org.jooby/jooby-apitool.svg)](https://javadoc.io/doc/org.jooby/jooby-apitool/1.5.0) +[![Maven](https://img.shields.io/maven-metadata/v/http/central.maven.org/maven2/org/jooby/jooby-apitool/maven-metadata.xml.svg)](http://mvnrepository.com/artifact/org.jooby/jooby-apitool/1.6.6) +[![javadoc](https://javadoc.io/badge/org.jooby/jooby-apitool.svg)](https://javadoc.io/doc/org.jooby/jooby-apitool/1.6.6) [![jooby-apitool website](https://img.shields.io/badge/jooby-apitool-brightgreen.svg)](http://jooby.org/doc/apitool) # API tool @@ -23,7 +23,7 @@ This module generates live documentation from your HTTP API (source code). org.jooby jooby-apitool - 1.5.0 + 1.6.6 ``` @@ -187,7 +187,7 @@ Go to ```build.gradle``` and add these lines: ```gradke buildscript { dependencies { - classpath group: 'org.jooby', name: 'jooby-gradle-plugin', version: '1.5.0' + classpath group: 'org.jooby', name: 'jooby-gradle-plugin', version: '1.6.6' } } apply plugin: 'jooby' diff --git a/modules/jooby-apitool/pom.xml b/modules/jooby-apitool/pom.xml index e2d6e35cb9..30da6e0040 100644 --- a/modules/jooby-apitool/pom.xml +++ b/modules/jooby-apitool/pom.xml @@ -6,7 +6,7 @@ org.jooby modules - 1.5.1-SNAPSHOT + 1.6.9 4.0.0 diff --git a/modules/jooby-apitool/src/main/java/org/jooby/internal/apitool/BytecodeRouteParser.java b/modules/jooby-apitool/src/main/java/org/jooby/internal/apitool/BytecodeRouteParser.java index df0d7d4844..07d0f6efb0 100644 --- a/modules/jooby-apitool/src/main/java/org/jooby/internal/apitool/BytecodeRouteParser.java +++ b/modules/jooby-apitool/src/main/java/org/jooby/internal/apitool/BytecodeRouteParser.java @@ -230,11 +230,13 @@ import org.jooby.apitool.RouteParameter; import org.jooby.apitool.RouteResponse; import org.jooby.funzy.Try; + import static org.jooby.funzy.When.when; + import org.jooby.internal.RouteMetadata; + import static org.jooby.internal.apitool.Filters.access; import static org.jooby.internal.apitool.Filters.and; -import static org.jooby.internal.apitool.Filters.call; import static org.jooby.internal.apitool.Filters.file; import static org.jooby.internal.apitool.Filters.getOrCreateKotlinClass; import static org.jooby.internal.apitool.Filters.is; @@ -249,7 +251,9 @@ import static org.jooby.internal.apitool.Filters.param; import static org.jooby.internal.apitool.Filters.path; import static org.jooby.internal.apitool.Filters.scriptRoute; +import static org.jooby.internal.apitool.Filters.sendObject; import static org.jooby.internal.apitool.Filters.use; + import org.jooby.internal.mvc.MvcRoutes; import org.jooby.mvc.Body; import org.jooby.mvc.Flash; @@ -259,8 +263,10 @@ import org.objectweb.asm.ClassReader; import org.objectweb.asm.Handle; import org.objectweb.asm.Opcodes; + import static org.objectweb.asm.Opcodes.GETSTATIC; import static org.objectweb.asm.Opcodes.INVOKESPECIAL; + import org.objectweb.asm.Type; import org.objectweb.asm.tree.AbstractInsnNode; import org.objectweb.asm.tree.ClassNode; @@ -321,7 +327,7 @@ public class BytecodeRouteParser { .isPresent(); static final Predicate SKIP = TYPE_TO_SKIP.and(ANNOTATION_TO_SKIP); - private static final ObjectMapper mapper = new ObjectMapper(); + static final ObjectMapper mapper = new ObjectMapper(); private static final String OBJECT = Type.getInternalName(Object.class); private static final String RETURN_OBJ = "L" + OBJECT + ";"; @@ -408,7 +414,7 @@ public List parse(String classname) throws Exception { java.lang.reflect.Type returnType; if (method.desc.endsWith("V")) { - returnType = void.class; + returnType = sendReturnType(loader, method); } else if (method.desc.endsWith(RETURN_OBJ)) { returnType = returnType(loader, method); } else { @@ -534,18 +540,24 @@ private List lambdas(final ClassLoader loader, final ClassNode owner, Me .findFirst() .map(MethodInsnNode.class::cast) .ifPresent(node -> { - List lambdas = lambdas(loader, loadClass(node.owner)).stream() - .filter(Lambda.class::isInstance) - .map(Lambda.class::cast) - .collect(Collectors.toList()); + List rlist = lambdas(loader, loadClass(node.owner)); + Insn.ldcFor(node).stream() .map(e -> e.cst.toString()) .findFirst() .ifPresent(prefix -> { - IntStream.range(0, lambdas.size()) - .forEach(i -> lambdas.set(i, lambdas.get(i).prefix(prefix))); + IntStream.range(0, rlist.size()) + .forEach(i -> { + Object o = rlist.get(i); + if (o instanceof Lambda) { + rlist.set(i, ((Lambda) o).prefix(prefix)); + } else { + RouteMethod r = (RouteMethod) o; + r.pattern(prefix + r.pattern()); + } + }); }); - result.addAll(lambdas); + result.addAll(rlist); }); }) .forEach(); @@ -699,22 +711,34 @@ private List kotlinLambda(final ClassLoader loader, final ClassNode owne new Insns(method) .on(scriptRoute, it -> { log.debug(" lambda candidate: {}", it.node); - it.prev() + String lambdaOwner = it.prev() + // Implicit request: get ("/") { ...}; .filter(and(is(FieldInsnNode.class), opcode(GETSTATIC))) .findFirst() .map(FieldInsnNode.class::cast) - .ifPresent(field -> { - ClassNode lambda = loadClass(field.owner); - log.debug(" lambda: {}", field.owner); - lambda.methods.stream() - .filter(kotlinRouteHandler()) - .forEach(e -> { - MethodNode m = (MethodNode) e; - log.debug(" implementation: {}.{}()", lambda.name, m.name, m.desc); - Lambda.create(field.owner, Optional.empty(), it.node, m) - .forEach(result::add); - }); + .map(f -> f.owner) + .orElseGet(() -> { + // Explicit request: get ("/") {req -> ...}; + return new Insn<>(method, it.node.getPrevious()) + .prev() + .filter(is(MethodInsnNode.class)) + .findFirst() + .map(MethodInsnNode.class::cast) + .map(m -> m.owner) + .orElse(null); }); + if (lambdaOwner != null) { + ClassNode lambda = loadClass(lambdaOwner); + log.debug(" lambda: {}", lambdaOwner); + lambda.methods.stream() + .filter(kotlinRouteHandler()) + .forEach(e -> { + MethodNode m = (MethodNode) e; + log.debug(" implementation: {}.{}()", lambda.name, m.name, m.desc); + Lambda.create(lambdaOwner, Optional.empty(), it.node, m) + .forEach(result::add); + }); + } }) // use(Mvc class) .on(use(loader, "org.jooby.Kooby"), it -> mvc(it, result::add)) @@ -724,7 +748,25 @@ private List kotlinLambda(final ClassLoader loader, final ClassNode owne .filter(and(is(MethodInsnNode.class), opcode(INVOKESPECIAL))) .findFirst() .map(MethodInsnNode.class::cast) - .ifPresent(n -> result.addAll(lambdas(loader, loadClass(n.owner)))); + .ifPresent(n -> { + List rlist = lambdas(loader, loadClass(n.owner)); + Insn.ldcFor(n).stream() + .map(e -> e.cst.toString()) + .findFirst() + .ifPresent(prefix -> { + IntStream.range(0, rlist.size()) + .forEach(i -> { + Object o = rlist.get(i); + if (o instanceof Lambda) { + rlist.set(i, ((Lambda) o).prefix(prefix)); + } else { + RouteMethod r = (RouteMethod) o; + r.pattern(prefix + r.pattern()); + } + }); + }); + result.addAll(rlist); + }); }) // path(String) {...} .on(path(loader, "org.jooby.Kooby"), it -> { @@ -1049,36 +1091,53 @@ private java.lang.reflect.Type returnType(final ClassLoader loader, .filter(and(is(InsnNode.class), opcode(Opcodes.ARETURN))) .findFirst() .map(AbstractInsnNode::getPrevious) - .map(previous -> { - /** return 1; return true; return new Foo(); */ - if (previous instanceof MethodInsnNode) { - MethodInsnNode minnsn = ((MethodInsnNode) previous); - if (minnsn.name.equals("")) { - return loadType(loader, minnsn.owner); - } - String desc = minnsn.desc; - java.lang.reflect.Type type = TypeDescriptorParser.parse(loader, desc); - if (type.getTypeName().equals(Result.class.getName())) { - return new TypeWithStatus(type, statusCodeFor(minnsn)); - } - return type; - } - /** return "String" | int | double */ - if (previous instanceof LdcInsnNode) { - Object cst = ((LdcInsnNode) previous).cst; - if (cst instanceof Type) { - return TypeDescriptorParser.parse(loader, ((Type) cst).getDescriptor()); - } - return cst.getClass(); - } - /** return variable */ - if (previous instanceof VarInsnNode) { - VarInsnNode varInsn = (VarInsnNode) previous; - return localVariable(loader, m, varInsn); - } + .map(previous -> handleReturnType(loader, m, previous)) + .orElseGet(() -> sendReturnType(loader, m)); + } - return Object.class; - }).orElse(Object.class); + private java.lang.reflect.Type handleReturnType(ClassLoader loader, MethodNode m, + AbstractInsnNode previous) { + /** return 1; return true; return new Foo(); */ + if (previous instanceof MethodInsnNode) { + MethodInsnNode minnsn = ((MethodInsnNode) previous); + if (minnsn.name.equals("")) { + return loadType(loader, minnsn.owner); + } + String desc = minnsn.desc; + java.lang.reflect.Type type = TypeDescriptorParser.parse(loader, desc); + if (type.getTypeName().equals(Result.class.getName())) { + return new TypeWithStatus(type, statusCodeFor(minnsn)); + } + return type; + } + /** return "String" | int | double */ + if (previous instanceof LdcInsnNode) { + Object cst = ((LdcInsnNode) previous).cst; + if (cst instanceof Type) { + return TypeDescriptorParser.parse(loader, ((Type) cst).getDescriptor()); + } + return cst.getClass(); + } + /** return variable */ + if (previous instanceof VarInsnNode) { + VarInsnNode varInsn = (VarInsnNode) previous; + return localVariable(loader, m, varInsn); + } + + return Object.class; + } + + private java.lang.reflect.Type sendReturnType(ClassLoader loader, MethodNode m) { + return new Insns(m) + .last() + .prev() + .filter(MethodInsnNode.class::isInstance) + .map(MethodInsnNode.class::cast) + .filter(sendObject()) + .findFirst() + .map(AbstractInsnNode::getPrevious) + .map(node -> handleReturnType(loader, m, node)) + .orElse(void.class); } private Integer statusCodeFor(MethodInsnNode node) { diff --git a/modules/jooby-apitool/src/main/java/org/jooby/internal/apitool/Filters.java b/modules/jooby-apitool/src/main/java/org/jooby/internal/apitool/Filters.java index 418cbad912..b29f8089c0 100644 --- a/modules/jooby-apitool/src/main/java/org/jooby/internal/apitool/Filters.java +++ b/modules/jooby-apitool/src/main/java/org/jooby/internal/apitool/Filters.java @@ -206,6 +206,7 @@ import org.jooby.Jooby; import org.jooby.Mutant; import org.jooby.Request; +import org.jooby.Response; import org.jooby.Route; import org.jooby.Router; import org.objectweb.asm.Opcodes; @@ -303,6 +304,10 @@ public static Predicate methodName(final String name) { return is(MethodNode.class).and(m -> m.name.equals(name)); } + public static Predicate sendObject() { + return call(Response.class, "send", Object.class.getName()); + } + @SuppressWarnings("rawtypes") public static Predicate method(final String name, final Object... args) { return is(MethodNode.class).and(m -> { diff --git a/modules/jooby-apitool/src/main/java/org/jooby/internal/apitool/Lambda.java b/modules/jooby-apitool/src/main/java/org/jooby/internal/apitool/Lambda.java index c6a6731462..e32b96c5a0 100644 --- a/modules/jooby-apitool/src/main/java/org/jooby/internal/apitool/Lambda.java +++ b/modules/jooby-apitool/src/main/java/org/jooby/internal/apitool/Lambda.java @@ -204,13 +204,18 @@ package org.jooby.internal.apitool; import org.jooby.Route; + import static org.jooby.internal.apitool.Insn.ldcFor; + import org.objectweb.asm.Handle; import org.objectweb.asm.Opcodes; import org.objectweb.asm.Type; +import org.objectweb.asm.tree.AbstractInsnNode; import org.objectweb.asm.tree.InvokeDynamicInsnNode; +import org.objectweb.asm.tree.LdcInsnNode; import org.objectweb.asm.tree.MethodInsnNode; import org.objectweb.asm.tree.MethodNode; +import org.objectweb.asm.tree.TypeInsnNode; import java.util.Arrays; import java.util.List; @@ -291,7 +296,30 @@ public static Stream create(String owner, Optional prefix, Metho List patterns = Insn.ldcFor(method).stream().map(it -> it.cst.toString()) .collect(Collectors.toList()); if (patterns.size() == 0) { - patterns.add("/"); + if (method.owner.equals("org/jooby/Kooby")) { + if (method.getPrevious() instanceof TypeInsnNode) { + // get(path) { req -> ...} + // seek and find first MethodInsnNode, which contains the path pattern. + AbstractInsnNode ldcpath = new Insn<>(implementation, method) + .prev() + .filter(Filters.is(TypeInsnNode.class)) + .flatMap(n -> { + if (n.getPrevious() instanceof LdcInsnNode) { + return Stream.of(n.getPrevious()); + } + return Stream.empty(); + }) + .findFirst() + .orElse(null); + if (ldcpath instanceof LdcInsnNode) { + patterns.add(((LdcInsnNode) ldcpath).cst.toString()); + } + } + } + // Still empty? use default + if (patterns.size() == 0) { + patterns.add("/"); + } } prefix.ifPresent(p -> { IntStream.range(0, patterns.size()) diff --git a/modules/jooby-apitool/src/main/java/org/jooby/internal/apitool/TypeDescriptorParser.java b/modules/jooby-apitool/src/main/java/org/jooby/internal/apitool/TypeDescriptorParser.java index 088c5cba67..e3037ac882 100644 --- a/modules/jooby-apitool/src/main/java/org/jooby/internal/apitool/TypeDescriptorParser.java +++ b/modules/jooby-apitool/src/main/java/org/jooby/internal/apitool/TypeDescriptorParser.java @@ -222,7 +222,7 @@ class TypeDescriptorParser extends SignatureVisitor { private int index; private TypeDescriptorParser(final ClassLoader loader) { - super(Opcodes.ASM5); + super(Opcodes.ASM7); this.loader = loader; } diff --git a/modules/jooby-apitool/src/main/java/org/jooby/internal/apitool/TypeJsonDeserializer.java b/modules/jooby-apitool/src/main/java/org/jooby/internal/apitool/TypeJsonDeserializer.java index 212088db9e..2414964c06 100644 --- a/modules/jooby-apitool/src/main/java/org/jooby/internal/apitool/TypeJsonDeserializer.java +++ b/modules/jooby-apitool/src/main/java/org/jooby/internal/apitool/TypeJsonDeserializer.java @@ -213,7 +213,6 @@ import java.lang.reflect.Array; import java.lang.reflect.Type; import java.util.ArrayList; -import java.util.Arrays; import java.util.List; class TypeJsonDeserializer extends JsonDeserializer { @@ -243,15 +242,23 @@ private static List parse(final ClassLoader loader, final String type, fin if (ch == '<') { Type owner = BytecodeRouteParser.loadType(loader, singleType.toString()); List parameters = parse(loader, type, i + 1); - return Arrays.asList( - Types.newParameterizedType(owner, parameters.toArray(new Type[parameters.size()]))); + types.add(Types.newParameterizedType(owner, parameters.toArray(new Type[parameters.size()]))); + return types; } else if (ch == ',') { Type element = BytecodeRouteParser.loadType(loader, singleType.toString()); types.add(element); singleType.setLength(0); } else if (ch == '>') { - Type element = BytecodeRouteParser.loadType(loader, singleType.toString()); - types.add(element); + if (singleType.length() > 0) { + Type element; + if (singleType.charAt(0) == '?') { + element = parseWildcardType(singleType, loader); + } else { + element = BytecodeRouteParser.loadType(loader, singleType.toString()); + } + types.add(element); + singleType.setLength(0); + } } else if (ch == ']') { // java.lang.String[] singleType.setLength(singleType.length() - 1); @@ -269,4 +276,29 @@ private static List parse(final ClassLoader loader, final String type, fin } return types; } + + private static Type parseWildcardType(final StringBuilder singleType, final ClassLoader loader) { + if(singleType.length() == 1) { + // Collection + return new MoreTypes.WildcardTypeImpl(new Type[]{Object.class}, MoreTypes.EMPTY_TYPE_ARRAY); + } + + Type type; + String typeStr; + switch (singleType.charAt(1)) { + case 'e': + // Collection> + typeStr = singleType.substring(8); + type = Types.subtypeOf(BytecodeRouteParser.loadType(loader, typeStr)); + break; + case 's': + // Collection> + typeStr = singleType.substring(6); + type = Types.supertypeOf(BytecodeRouteParser.loadType(loader, typeStr)); + break; + default: + throw new UnsupportedOperationException("Unsupported wildcard type"); + } + return type; + } } diff --git a/modules/jooby-apitool/src/test/java/apps/App1276.java b/modules/jooby-apitool/src/test/java/apps/App1276.java new file mode 100644 index 0000000000..b552d58ab9 --- /dev/null +++ b/modules/jooby-apitool/src/test/java/apps/App1276.java @@ -0,0 +1,10 @@ +package apps; + +import org.jooby.Jooby; + +public class App1276 extends Jooby { + + { + use("/namespace", new App1276b()); + } +} diff --git a/modules/jooby-apitool/src/test/java/apps/App1276b.java b/modules/jooby-apitool/src/test/java/apps/App1276b.java new file mode 100644 index 0000000000..bf42adc751 --- /dev/null +++ b/modules/jooby-apitool/src/test/java/apps/App1276b.java @@ -0,0 +1,12 @@ +package apps; + +import org.jooby.Jooby; + +public class App1276b extends Jooby { + + { + use(Controller1276.class); + + get("/foo", () -> { return "I'm listed"; }); + } +} diff --git a/modules/jooby-apitool/src/test/java/apps/Controller1276.java b/modules/jooby-apitool/src/test/java/apps/Controller1276.java new file mode 100644 index 0000000000..924dad9826 --- /dev/null +++ b/modules/jooby-apitool/src/test/java/apps/Controller1276.java @@ -0,0 +1,10 @@ +package apps; + +import org.jooby.mvc.Path; + +public class Controller1276 { + @Path("/1176") + public String foo() { + return ""; + } +} diff --git a/modules/jooby-apitool/src/test/java/issues/Issue1072.java b/modules/jooby-apitool/src/test/java/issues/Issue1072.java index 0f8ed5683c..848fed9058 100644 --- a/modules/jooby-apitool/src/test/java/issues/Issue1072.java +++ b/modules/jooby-apitool/src/test/java/issues/Issue1072.java @@ -41,7 +41,7 @@ public void shouldContainsSwaggerResponseDescription() throws Exception { + " operationId: \"get\"\n" + " parameters: []\n" + " responses:\n" - + " 200:\n" + + " \"200\":\n" + " description: \"Person\"\n" + " schema:\n" + " $ref: \"#/definitions/Person\"\n" diff --git a/modules/jooby-apitool/src/test/java/issues/Issue1073.java b/modules/jooby-apitool/src/test/java/issues/Issue1073.java index 4e86016e57..c7c1b5f3c0 100644 --- a/modules/jooby-apitool/src/test/java/issues/Issue1073.java +++ b/modules/jooby-apitool/src/test/java/issues/Issue1073.java @@ -35,7 +35,7 @@ public void zonedDateMustUseDateTimeFormat() throws Exception { + " type: \"string\"\n" + " format: \"date-time\"\n" + " responses:\n" - + " 200:\n" + + " \"200\":\n" + " description: \"News\"\n" + " schema:\n" + " $ref: \"#/definitions/News\"\n" diff --git a/modules/jooby-apitool/src/test/java/issues/Issue1074.java b/modules/jooby-apitool/src/test/java/issues/Issue1074.java index 92ccbe6646..515bc068f3 100644 --- a/modules/jooby-apitool/src/test/java/issues/Issue1074.java +++ b/modules/jooby-apitool/src/test/java/issues/Issue1074.java @@ -63,7 +63,7 @@ public void shouldDetectKotlinTypeUsingOptionalParameters() throws Exception { + " type: \"integer\"\n" + " format: \"int32\"\n" + " responses:\n" - + " 200:\n" + + " \"200\":\n" + " description: \"String\"\n" + " schema:\n" + " type: \"string\"\n", yaml(swagger(routes))); diff --git a/modules/jooby-apitool/src/test/java/issues/Issue1075.java b/modules/jooby-apitool/src/test/java/issues/Issue1075.java index 6eaed53122..6c95d455b6 100644 --- a/modules/jooby-apitool/src/test/java/issues/Issue1075.java +++ b/modules/jooby-apitool/src/test/java/issues/Issue1075.java @@ -32,7 +32,7 @@ public void shouldGenerateUniqueOperationIds() throws Exception { + " operationId: \"getOrders\"\n" + " parameters: []\n" + " responses:\n" - + " 200:\n" + + " \"200\":\n" + " description: \"List[String]\"\n" + " schema:\n" + " type: \"array\"\n" @@ -50,7 +50,7 @@ public void shouldGenerateUniqueOperationIds() throws Exception { + " type: \"integer\"\n" + " format: \"int32\"\n" + " responses:\n" - + " 200:\n" + + " \"200\":\n" + " description: \"int\"\n" + " schema:\n" + " type: \"integer\"\n" @@ -62,7 +62,7 @@ public void shouldGenerateUniqueOperationIds() throws Exception { + " operationId: \"getProducts\"\n" + " parameters: []\n" + " responses:\n" - + " 200:\n" + + " \"200\":\n" + " description: \"List[String]\"\n" + " schema:\n" + " type: \"array\"\n" diff --git a/modules/jooby-apitool/src/test/java/issues/Issue1096.java b/modules/jooby-apitool/src/test/java/issues/Issue1096.java index dfb06dbd9d..43f0299717 100644 --- a/modules/jooby-apitool/src/test/java/issues/Issue1096.java +++ b/modules/jooby-apitool/src/test/java/issues/Issue1096.java @@ -81,7 +81,7 @@ public void shouldExpandQueryBean() throws Exception { + " required: false\n" + " type: \"string\"\n" + " responses:\n" - + " 200:\n" + + " \"200\":\n" + " description: \"String\"\n" + " schema:\n" + " type: \"string\"\n", yaml(swagger(routes))); @@ -155,7 +155,7 @@ public void shouldExpandForm() throws Exception { + " required: false\n" + " type: \"file\"\n" + " responses:\n" - + " 200:\n" + + " \"200\":\n" + " description: \"String\"\n" + " schema:\n" + " type: \"string\"\n", yaml(swagger(routes))); @@ -229,7 +229,7 @@ public void shouldExpandFormMvc() throws Exception { + " required: false\n" + " type: \"file\"\n" + " responses:\n" - + " 200:\n" + + " \"200\":\n" + " description: \"String\"\n" + " schema:\n" + " type: \"string\"\n", yaml(swagger(routes))); @@ -296,7 +296,7 @@ public void shouldExpandQueryBeanFromMvc() throws Exception { + " required: false\n" + " type: \"string\"\n" + " responses:\n" - + " 200:\n" + + " \"200\":\n" + " description: \"String\"\n" + " schema:\n" + " type: \"string\"\n", yaml(swagger(routes))); @@ -350,7 +350,7 @@ public void shouldExpandQueryBeanFromKotlin() throws Exception { + " required: true\n" + " type: \"string\"\n" + " responses:\n" - + " 200:\n" + + " \"200\":\n" + " description: \"String\"\n" + " schema:\n" + " type: \"string\"\n", yaml(swagger(routes))); diff --git a/modules/jooby-apitool/src/test/java/issues/Issue1097.java b/modules/jooby-apitool/src/test/java/issues/Issue1097.java index 4259e4487f..0f876fd3bd 100644 --- a/modules/jooby-apitool/src/test/java/issues/Issue1097.java +++ b/modules/jooby-apitool/src/test/java/issues/Issue1097.java @@ -36,7 +36,7 @@ public void shouldUseCustomTagger() throws Exception { + " operationId: \"getSong\"\n" + " parameters: []\n" + " responses:\n" - + " 200:\n" + + " \"200\":\n" + " description: \"String\"\n" + " schema:\n" + " type: \"string\"\n" @@ -47,7 +47,7 @@ public void shouldUseCustomTagger() throws Exception { + " operationId: \"getAlbum\"\n" + " parameters: []\n" + " responses:\n" - + " 200:\n" + + " \"200\":\n" + " description: \"String\"\n" + " schema:\n" + " type: \"string\"\n" @@ -58,7 +58,7 @@ public void shouldUseCustomTagger() throws Exception { + " operationId: \"getArtist\"\n" + " parameters: []\n" + " responses:\n" - + " 200:\n" + + " \"200\":\n" + " description: \"String\"\n" + " schema:\n" + " type: \"string\"\n", Yaml diff --git a/modules/jooby-apitool/src/test/java/issues/Issue1100.java b/modules/jooby-apitool/src/test/java/issues/Issue1100.java index acea3a73a7..bceafc538c 100644 --- a/modules/jooby-apitool/src/test/java/issues/Issue1100.java +++ b/modules/jooby-apitool/src/test/java/issues/Issue1100.java @@ -41,7 +41,7 @@ public void apiOperation() throws Exception { + " - \" bar/baz\"\n" + " parameters: []\n" + " responses:\n" - + " 202:\n" + + " \"202\":\n" + " description: \"Result\"\n" + " headers:\n" + " foo:\n" @@ -56,7 +56,7 @@ public void apiOperation() throws Exception { + " operationId: \"/Controller1100.listApiResponse\"\n" + " parameters: []\n" + " responses:\n" - + " 204:\n" + + " \"204\":\n" + " description: \"Response message\"\n" + " headers:\n" + " foo:\n" @@ -70,11 +70,11 @@ public void apiOperation() throws Exception { + " operationId: \"/Controller1100.listNApiResponse\"\n" + " parameters: []\n" + " responses:\n" - + " 200:\n" + + " \"200\":\n" + " description: \"cat\"\n" + " schema:\n" + " $ref: \"#/definitions/Category\"\n" - + " 200(Tag):\n" + + " \"200(Tag)\":\n" + " description: \"tag\"\n" + " headers:\n" + " foo:\n" diff --git a/modules/jooby-apitool/src/test/java/issues/Issue1126.java b/modules/jooby-apitool/src/test/java/issues/Issue1126.java index 93a3979f98..cced516012 100644 --- a/modules/jooby-apitool/src/test/java/issues/Issue1126.java +++ b/modules/jooby-apitool/src/test/java/issues/Issue1126.java @@ -36,7 +36,7 @@ public void bodySchemaRefVsFormData() throws Exception { + " schema:\n" + " $ref: \"#/definitions/PingCommand\"\n" + " responses:\n" - + " 200:\n" + + " \"200\":\n" + " description: \"Boolean\"\n" + " schema:\n" + " type: \"boolean\"\n" @@ -59,7 +59,7 @@ public void bodySchemaRefVsFormData() throws Exception { + " type: \"integer\"\n" + " format: \"int32\"\n" + " responses:\n" - + " 200:\n" + + " \"200\":\n" + " description: \"Boolean\"\n" + " schema:\n" + " type: \"boolean\"\n" diff --git a/modules/jooby-apitool/src/test/java/issues/Issue1182.java b/modules/jooby-apitool/src/test/java/issues/Issue1182.java index b8953b55e6..b8e963e0b9 100644 --- a/modules/jooby-apitool/src/test/java/issues/Issue1182.java +++ b/modules/jooby-apitool/src/test/java/issues/Issue1182.java @@ -42,7 +42,7 @@ public void shouldProcessApiParamSwaggerAnnotation() throws Exception { + " required: false\n" + " type: \"string\"\n" + " responses:\n" - + " 200:\n" + + " \"200\":\n" + " description: \"String\"\n", yaml(swagger(routes), false)); } diff --git a/modules/jooby-apitool/src/test/java/issues/Issue1235.java b/modules/jooby-apitool/src/test/java/issues/Issue1235.java new file mode 100644 index 0000000000..ab5da93e9f --- /dev/null +++ b/modules/jooby-apitool/src/test/java/issues/Issue1235.java @@ -0,0 +1,52 @@ +package issues; + +import kt.App1235; +import org.jooby.apitool.ApiParser; +import org.jooby.apitool.ApiToolFeature; +import org.jooby.apitool.RouteMethod; +import org.jooby.apitool.RouteMethodAssert; +import org.junit.Test; + +import java.util.List; + +public class Issue1235 extends ApiToolFeature { + + @Test + public void shouldSupportExplicitRequestHandler() throws Exception { + List routes = new ApiParser(dir()).parseFully(new App1235()); + new RouteMethodAssert(routes) + .next(r -> { + r.returnType("com.typesafe.config.Config"); + r.method("GET"); + r.pattern("/qwe"); + r.description(null); + r.summary(null); + r.returns(null); + }) + .next(r -> { + r.returnType("com.typesafe.config.Config"); + r.method("GET"); + r.pattern("/asd"); + r.description(null); + r.summary(null); + r.returns(null); + }) + .next(r -> { + r.returnType("com.typesafe.config.Config"); + r.method("GET"); + r.pattern("/zxc"); + r.description(null); + r.summary(null); + r.returns(null); + }) + .next(r -> { + r.returnType("com.typesafe.config.Config"); + r.method("GET"); + r.pattern("/rty"); + r.description(null); + r.summary(null); + r.returns(null); + }) + .done(); + } +} diff --git a/modules/jooby-apitool/src/test/java/issues/Issue1261.java b/modules/jooby-apitool/src/test/java/issues/Issue1261.java new file mode 100644 index 0000000000..f85dd5e396 --- /dev/null +++ b/modules/jooby-apitool/src/test/java/issues/Issue1261.java @@ -0,0 +1,28 @@ +package issues; + +import kt.App1261; +import org.jooby.apitool.ApiParser; +import org.jooby.apitool.ApiToolFeature; +import org.jooby.apitool.RouteMethod; +import org.jooby.apitool.RouteMethodAssert; +import org.junit.Test; + +import java.util.List; + +public class Issue1261 extends ApiToolFeature { + + @Test + public void shouldContainsSwaggerResponseDescription() throws Exception { + List routes = new ApiParser(dir()).parseFully(new App1261()); + new RouteMethodAssert(routes) + .next(r -> { + r.returnType("kt.ResultData"); + r.method("GET"); + r.pattern("/"); + r.description(null); + r.summary(null); + r.returns(null); + }) + .done(); + } +} diff --git a/modules/jooby-apitool/src/test/java/issues/Issue1276.java b/modules/jooby-apitool/src/test/java/issues/Issue1276.java new file mode 100644 index 0000000000..058e88056f --- /dev/null +++ b/modules/jooby-apitool/src/test/java/issues/Issue1276.java @@ -0,0 +1,53 @@ +package issues; + +import apps.App1276; +import org.jooby.apitool.ApiParser; +import org.jooby.apitool.ApiToolFeature; +import org.jooby.apitool.RouteMethod; +import org.junit.Test; + +import java.util.List; + +import static org.junit.Assert.assertEquals; + +public class Issue1276 extends ApiToolFeature { + + @Test + public void apitoolDoesNotListMvcNamespaced () throws Exception { + List routes = new ApiParser(dir()).parseFully(new App1276()); + + assertEquals("---\n" + + "swagger: \"2.0\"\n" + + "tags:\n" + + "- name: \"/namespace/1176\"\n" + + "- name: \"/namespace/foo\"\n" + + "consumes:\n" + + "- \"application/json\"\n" + + "produces:\n" + + "- \"application/json\"\n" + + "paths:\n" + + " /namespace/1176:\n" + + " get:\n" + + " tags:\n" + + " - \"/namespace/1176\"\n" + + " operationId: \"/Controller1276.foo\"\n" + + " parameters: []\n" + + " responses:\n" + + " \"200\":\n" + + " description: \"String\"\n" + + " schema:\n" + + " type: \"string\"\n" + + " /namespace/foo:\n" + + " get:\n" + + " tags:\n" + + " - \"/namespace/foo\"\n" + + " operationId: \"getNamespacefoo\"\n" + + " parameters: []\n" + + " responses:\n" + + " \"200\":\n" + + " description: \"String\"\n" + + " schema:\n" + + " type: \"string\"\n", yaml(swagger(routes), false)); + } + +} diff --git a/modules/jooby-apitool/src/test/java/issues/Issue1300.java b/modules/jooby-apitool/src/test/java/issues/Issue1300.java new file mode 100644 index 0000000000..e333b4146b --- /dev/null +++ b/modules/jooby-apitool/src/test/java/issues/Issue1300.java @@ -0,0 +1,54 @@ +package issues; + +import kt.App1300; +import org.jooby.apitool.ApiParser; +import org.jooby.apitool.ApiToolFeature; +import org.jooby.apitool.RouteMethod; +import org.junit.Test; + +import java.util.List; + +import static org.junit.Assert.assertEquals; + +public class Issue1300 extends ApiToolFeature { + + @Test + public void apitoolDoesNotListMvcNamespaced () throws Exception { + List routes = new ApiParser(dir()).parseFully(new App1300()); + + assertEquals("---\n" + + "swagger: \"2.0\"\n" + + "tags:\n" + + "- name: \"/route\"\n" + + "- name: \"/subroute/hello\"\n" + + "consumes:\n" + + "- \"application/json\"\n" + + "produces:\n" + + "- \"application/json\"\n" + + "paths:\n" + + " /route:\n" + + " get:\n" + + " tags:\n" + + " - \"/route\"\n" + + " operationId: \"getRoute\"\n" + + " parameters: []\n" + + " responses:\n" + + " \"200\":\n" + + " description: \"int\"\n" + + " schema:\n" + + " type: \"integer\"\n" + + " format: \"int32\"\n" + + " /subroute/hello:\n" + + " get:\n" + + " tags:\n" + + " - \"/subroute/hello\"\n" + + " operationId: \"getSubroutehello\"\n" + + " parameters: []\n" + + " responses:\n" + + " \"200\":\n" + + " description: \"String\"\n" + + " schema:\n" + + " type: \"string\"\n", yaml(swagger(routes), false)); + } + +} diff --git a/modules/jooby-apitool/src/test/java/kt/App1235.kt b/modules/jooby-apitool/src/test/java/kt/App1235.kt new file mode 100644 index 0000000000..ca222504a2 --- /dev/null +++ b/modules/jooby-apitool/src/test/java/kt/App1235.kt @@ -0,0 +1,23 @@ +package kt + +import com.typesafe.config.Config +import org.jooby.* + +fun main(args: Array) { + org.jooby.run(::App1235, *args) +} + +class App1235 : Kooby({ + get("/qwe") { req -> + require(Config::class.java) + } + get("/asd") { req -> + require(Config::class.java) + } + get("/zxc") { req -> + require(Config::class.java) + } + get("/rty") { req -> + require(Config::class.java) + } +}) diff --git a/modules/jooby-apitool/src/test/java/kt/App1261.kt b/modules/jooby-apitool/src/test/java/kt/App1261.kt new file mode 100644 index 0000000000..70bd4d1a26 --- /dev/null +++ b/modules/jooby-apitool/src/test/java/kt/App1261.kt @@ -0,0 +1,15 @@ +package kt + +import org.jooby.* + +data class ResultData( + val text: String, + val number: Int +) + +class App1261 : Kooby({ + get("/") {req, rsp -> + val response = ResultData("Test", 123) + rsp.send(response) + } +}) diff --git a/modules/jooby-apitool/src/test/java/kt/App1300.kt b/modules/jooby-apitool/src/test/java/kt/App1300.kt new file mode 100644 index 0000000000..8387a96b8d --- /dev/null +++ b/modules/jooby-apitool/src/test/java/kt/App1300.kt @@ -0,0 +1,11 @@ +package kt + +import org.jooby.Kooby + +class App1300 : Kooby({ + get("route") { + 123 + } + + use("subroute", SubRoute1300()) +}) diff --git a/modules/jooby-apitool/src/test/java/kt/SubRoute1300.kt b/modules/jooby-apitool/src/test/java/kt/SubRoute1300.kt new file mode 100644 index 0000000000..08a17e8078 --- /dev/null +++ b/modules/jooby-apitool/src/test/java/kt/SubRoute1300.kt @@ -0,0 +1,9 @@ +package kt + +import org.jooby.Kooby + +class SubRoute1300 : Kooby({ + get("hello") { + "word" + } +}) diff --git a/modules/jooby-apitool/src/test/java/org/jooby/internal/apitool/ComplexMapTypesTest.java b/modules/jooby-apitool/src/test/java/org/jooby/internal/apitool/ComplexMapTypesTest.java new file mode 100644 index 0000000000..d7cc5b2e1a --- /dev/null +++ b/modules/jooby-apitool/src/test/java/org/jooby/internal/apitool/ComplexMapTypesTest.java @@ -0,0 +1,60 @@ +package org.jooby.internal.apitool; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.google.inject.util.Types; +import org.junit.Test; + +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; +import java.util.UUID; + +import static org.junit.Assert.assertEquals; + +public class ComplexMapTypesTest { + + public static class TypeWrapper { + private Type type; + + public Type getType() { + return type; + } + + public void setType(Type type) { + this.type = type; + } + } + + @Test + public void shouldDeserializeMapWithListProperly() throws Exception { + ObjectMapper mapper = BytecodeRouteParser.mapper; + TypeWrapper expected = new TypeWrapper(); + ParameterizedType type = Types.mapOf(UUID.class, Types.listOf(Integer.class)); + expected.setType(type); + String json = mapper.writeValueAsString(expected); + TypeWrapper actual = mapper.readValue(json, TypeWrapper.class); + assertEquals(expected.getType(), actual.getType()); + } + + @Test + public void shouldDeserializeMapWithMapWithListProperly() throws Exception { + ObjectMapper mapper = BytecodeRouteParser.mapper; + TypeWrapper expected = new TypeWrapper(); + ParameterizedType type = Types.mapOf(UUID.class, Types.mapOf(UUID.class, Types.listOf(Integer.class))); + expected.setType(type); + String json = mapper.writeValueAsString(expected); + TypeWrapper actual = mapper.readValue(json, TypeWrapper.class); + assertEquals(expected.getType(), actual.getType()); + } + + @Test + public void shouldDeserializeListWithMapWithListProperly() throws Exception { + ObjectMapper mapper = BytecodeRouteParser.mapper; + TypeWrapper expected = new TypeWrapper(); + ParameterizedType type = Types.listOf(Types.mapOf(UUID.class, Types.mapOf(UUID.class, Types.listOf(Integer.class)))); + expected.setType(type); + String json = mapper.writeValueAsString(expected); + TypeWrapper actual = mapper.readValue(json, TypeWrapper.class); + assertEquals(expected.getType(), actual.getType()); + } + +} diff --git a/modules/jooby-apitool/src/test/java/org/jooby/internal/apitool/Issue1230.java b/modules/jooby-apitool/src/test/java/org/jooby/internal/apitool/Issue1230.java new file mode 100644 index 0000000000..f2cbfa749d --- /dev/null +++ b/modules/jooby-apitool/src/test/java/org/jooby/internal/apitool/Issue1230.java @@ -0,0 +1,38 @@ +package org.jooby.internal.apitool; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.google.inject.util.Types; +import org.jooby.apitool.ApiToolFeature; +import org.junit.Test; + +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; + +import static org.junit.Assert.assertEquals; + +public class Issue1230 extends ApiToolFeature { + + public static class I1230 { + + private Type type; + + public Type getType() { + return type; + } + + public void setType(Type type) { + this.type = type; + } + } + + @Test + public void shouldDeserializeComplexTypePropertly() throws Exception { + ObjectMapper mapper = BytecodeRouteParser.mapper; + I1230 expected = new I1230(); + ParameterizedType type = Types.listOf(Types.listOf(Integer.class)); + expected.setType(type); + String json = mapper.writeValueAsString(expected); + I1230 actual = mapper.readValue(json, I1230.class); + assertEquals(expected.getType(), actual.getType()); + } +} diff --git a/modules/jooby-apitool/src/test/java/org/jooby/internal/apitool/WildcardTypesTest.java b/modules/jooby-apitool/src/test/java/org/jooby/internal/apitool/WildcardTypesTest.java new file mode 100644 index 0000000000..c057a2c61a --- /dev/null +++ b/modules/jooby-apitool/src/test/java/org/jooby/internal/apitool/WildcardTypesTest.java @@ -0,0 +1,59 @@ +package org.jooby.internal.apitool; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.google.inject.internal.MoreTypes; +import com.google.inject.util.Types; +import org.junit.Test; + +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; + +import static org.junit.Assert.assertEquals; + +public class WildcardTypesTest { + + public static class TypeWrapper { + private Type type; + + public Type getType() { + return type; + } + + public void setType(Type type) { + this.type = type; + } + } + + @Test + public void shouldDeserializeSubtypeProperly() throws Exception { + ObjectMapper mapper = BytecodeRouteParser.mapper; + TypeWrapper expected = new TypeWrapper(); + ParameterizedType type = Types.listOf(Types.subtypeOf(Integer.class)); + expected.setType(type); + String json = mapper.writeValueAsString(expected); + TypeWrapper actual = mapper.readValue(json, TypeWrapper.class); + assertEquals(expected.getType(), actual.getType()); + } + + @Test + public void shouldDeserializeSuperTypeProperly() throws Exception { + ObjectMapper mapper = BytecodeRouteParser.mapper; + TypeWrapper expected = new TypeWrapper(); + ParameterizedType type = Types.listOf(Types.supertypeOf(Integer.class)); + expected.setType(type); + String json = mapper.writeValueAsString(expected); + TypeWrapper actual = mapper.readValue(json, TypeWrapper.class); + assertEquals(expected.getType(), actual.getType()); + } + + @Test + public void shouldDeserializeUnknownTypeProperly() throws Exception { + ObjectMapper mapper = BytecodeRouteParser.mapper; + TypeWrapper expected = new TypeWrapper(); + ParameterizedType type = Types.listOf(new MoreTypes.WildcardTypeImpl(new Type[]{Object.class}, MoreTypes.EMPTY_TYPE_ARRAY)); + expected.setType(type); + String json = mapper.writeValueAsString(expected); + TypeWrapper actual = mapper.readValue(json, TypeWrapper.class); + assertEquals(expected.getType(), actual.getType()); + } +} diff --git a/modules/jooby-archetype/pom.xml b/modules/jooby-archetype/pom.xml index 4fa804482e..ce7bd5943f 100644 --- a/modules/jooby-archetype/pom.xml +++ b/modules/jooby-archetype/pom.xml @@ -7,7 +7,7 @@ org.jooby modules - 1.5.1-SNAPSHOT + 1.6.9 jooby-archetype diff --git a/modules/jooby-assets-autoprefixer/README.md b/modules/jooby-assets-autoprefixer/README.md index e7f15dc18c..a3f243b38a 100644 --- a/modules/jooby-assets-autoprefixer/README.md +++ b/modules/jooby-assets-autoprefixer/README.md @@ -1,5 +1,5 @@ -[![Maven Central](https://maven-badges.herokuapp.com/maven-central/org.jooby/jooby-assets-autoprefixer/badge.svg)](https://maven-badges.herokuapp.com/maven-central/org.jooby/jooby-assets-autoprefixer) -[![javadoc](https://javadoc.io/badge/org.jooby/jooby-assets-autoprefixer.svg)](https://javadoc.io/doc/org.jooby/jooby-assets-autoprefixer/1.5.0) +[![Maven](https://img.shields.io/maven-metadata/v/http/central.maven.org/maven2/org/jooby/jooby-assets-autoprefixer/maven-metadata.xml.svg)](http://mvnrepository.com/artifact/org.jooby/jooby-assets-autoprefixer/1.6.6) +[![javadoc](https://javadoc.io/badge/org.jooby/jooby-assets-autoprefixer.svg)](https://javadoc.io/doc/org.jooby/jooby-assets-autoprefixer/1.6.6) [![jooby-assets-autoprefixer website](https://img.shields.io/badge/jooby-assets-autoprefixer-brightgreen.svg)](http://jooby.org/doc/assets-autoprefixer) # auto-prefixer @@ -12,8 +12,8 @@ Make sure you've already set up the [assets module](https://github.com/jooby-pro ```xml org.jooby - jooby-assets-auto-prefixer - 1.5.0 + jooby-assets-autoprefixer + 1.6.6 provided ``` diff --git a/modules/jooby-assets-autoprefixer/pom.xml b/modules/jooby-assets-autoprefixer/pom.xml index d79c8634a5..a12c9516fc 100644 --- a/modules/jooby-assets-autoprefixer/pom.xml +++ b/modules/jooby-assets-autoprefixer/pom.xml @@ -5,7 +5,7 @@ org.jooby modules - 1.5.1-SNAPSHOT + 1.6.9 4.0.0 diff --git a/modules/jooby-assets-babel/README.md b/modules/jooby-assets-babel/README.md index 1d27c858c4..e8f822972f 100644 --- a/modules/jooby-assets-babel/README.md +++ b/modules/jooby-assets-babel/README.md @@ -1,5 +1,5 @@ -[![Maven Central](https://maven-badges.herokuapp.com/maven-central/org.jooby/jooby-assets-babel/badge.svg)](https://maven-badges.herokuapp.com/maven-central/org.jooby/jooby-assets-babel) -[![javadoc](https://javadoc.io/badge/org.jooby/jooby-assets-babel.svg)](https://javadoc.io/doc/org.jooby/jooby-assets-babel/1.5.0) +[![Maven](https://img.shields.io/maven-metadata/v/http/central.maven.org/maven2/org/jooby/jooby-assets-babel/maven-metadata.xml.svg)](http://mvnrepository.com/artifact/org.jooby/jooby-assets-babel/1.6.6) +[![javadoc](https://javadoc.io/badge/org.jooby/jooby-assets-babel.svg)](https://javadoc.io/doc/org.jooby/jooby-assets-babel/1.6.6) [![jooby-assets-babel website](https://img.shields.io/badge/jooby-assets-babel-brightgreen.svg)](http://jooby.org/doc/assets-babel) # babel @@ -13,7 +13,7 @@ Make sure you've already set up the [assets module](https://github.com/jooby-pro org.jooby jooby-assets-babel - 1.5.0 + 1.6.6 provided ``` @@ -38,7 +38,7 @@ assets { org.jooby jooby-assets-babel - 1.5.0 + 1.6.6 provided ``` diff --git a/modules/jooby-assets-babel/pom.xml b/modules/jooby-assets-babel/pom.xml index b3a865c469..1ea6f20c63 100644 --- a/modules/jooby-assets-babel/pom.xml +++ b/modules/jooby-assets-babel/pom.xml @@ -5,7 +5,7 @@ org.jooby modules - 1.5.1-SNAPSHOT + 1.6.9 4.0.0 diff --git a/modules/jooby-assets-clean-css/README.md b/modules/jooby-assets-clean-css/README.md index 8cbeb64401..554007e223 100644 --- a/modules/jooby-assets-clean-css/README.md +++ b/modules/jooby-assets-clean-css/README.md @@ -1,5 +1,5 @@ -[![Maven Central](https://maven-badges.herokuapp.com/maven-central/org.jooby/jooby-assets-clean-css/badge.svg)](https://maven-badges.herokuapp.com/maven-central/org.jooby/jooby-assets-clean-css) -[![javadoc](https://javadoc.io/badge/org.jooby/jooby-assets-clean-css.svg)](https://javadoc.io/doc/org.jooby/jooby-assets-clean-css/1.5.0) +[![Maven](https://img.shields.io/maven-metadata/v/http/central.maven.org/maven2/org/jooby/jooby-assets-clean-css/maven-metadata.xml.svg)](http://mvnrepository.com/artifact/org.jooby/jooby-assets-clean-css/1.6.6) +[![javadoc](https://javadoc.io/badge/org.jooby/jooby-assets-clean-css.svg)](https://javadoc.io/doc/org.jooby/jooby-assets-clean-css/1.6.6) [![jooby-assets-clean-css website](https://img.shields.io/badge/jooby-assets-clean-css-brightgreen.svg)](http://jooby.org/doc/assets-clean-css) # clean-css @@ -13,7 +13,7 @@ Make sure you've already set up the [assets module](https://github.com/jooby-pro org.jooby jooby-assets-clean-css - 1.5.0 + 1.6.6 provided ``` diff --git a/modules/jooby-assets-clean-css/pom.xml b/modules/jooby-assets-clean-css/pom.xml index 8c94aaa030..f7585227b1 100644 --- a/modules/jooby-assets-clean-css/pom.xml +++ b/modules/jooby-assets-clean-css/pom.xml @@ -5,7 +5,7 @@ org.jooby modules - 1.5.1-SNAPSHOT + 1.6.9 4.0.0 diff --git a/modules/jooby-assets-closure-compiler/README.md b/modules/jooby-assets-closure-compiler/README.md index 749e324b06..81098cc184 100644 --- a/modules/jooby-assets-closure-compiler/README.md +++ b/modules/jooby-assets-closure-compiler/README.md @@ -1,5 +1,5 @@ -[![Maven Central](https://maven-badges.herokuapp.com/maven-central/org.jooby/jooby-assets-closure-compiler/badge.svg)](https://maven-badges.herokuapp.com/maven-central/org.jooby/jooby-assets-closure-compiler) -[![javadoc](https://javadoc.io/badge/org.jooby/jooby-assets-closure-compiler.svg)](https://javadoc.io/doc/org.jooby/jooby-assets-closure-compiler/1.5.0) +[![Maven](https://img.shields.io/maven-metadata/v/http/central.maven.org/maven2/org/jooby/jooby-assets-closure-compiler/maven-metadata.xml.svg)](http://mvnrepository.com/artifact/org.jooby/jooby-assets-closure-compiler/1.6.6) +[![javadoc](https://javadoc.io/badge/org.jooby/jooby-assets-closure-compiler.svg)](https://javadoc.io/doc/org.jooby/jooby-assets-closure-compiler/1.6.6) [![jooby-assets-closure-compiler website](https://img.shields.io/badge/jooby-assets-closure-compiler-brightgreen.svg)](http://jooby.org/doc/assets-closure-compiler) # closure-compiler @@ -13,7 +13,7 @@ Make sure you've already set up the [assets module](https://github.com/jooby-pro org.jooby jooby-assets-closure-compiler - 1.5.0 + 1.6.6 provided ``` diff --git a/modules/jooby-assets-closure-compiler/pom.xml b/modules/jooby-assets-closure-compiler/pom.xml index 49ceb9a193..3fa5d70719 100644 --- a/modules/jooby-assets-closure-compiler/pom.xml +++ b/modules/jooby-assets-closure-compiler/pom.xml @@ -5,7 +5,7 @@ org.jooby modules - 1.5.1-SNAPSHOT + 1.6.9 4.0.0 diff --git a/modules/jooby-assets-csslint/README.md b/modules/jooby-assets-csslint/README.md index 99d15299e7..2aed9b1614 100644 --- a/modules/jooby-assets-csslint/README.md +++ b/modules/jooby-assets-csslint/README.md @@ -1,5 +1,5 @@ -[![Maven Central](https://maven-badges.herokuapp.com/maven-central/org.jooby/jooby-assets-csslint/badge.svg)](https://maven-badges.herokuapp.com/maven-central/org.jooby/jooby-assets-csslint) -[![javadoc](https://javadoc.io/badge/org.jooby/jooby-assets-csslint.svg)](https://javadoc.io/doc/org.jooby/jooby-assets-csslint/1.5.0) +[![Maven](https://img.shields.io/maven-metadata/v/http/central.maven.org/maven2/org/jooby/jooby-assets-csslint/maven-metadata.xml.svg)](http://mvnrepository.com/artifact/org.jooby/jooby-assets-csslint/1.6.6) +[![javadoc](https://javadoc.io/badge/org.jooby/jooby-assets-csslint.svg)](https://javadoc.io/doc/org.jooby/jooby-assets-csslint/1.6.6) [![jooby-assets-csslint website](https://img.shields.io/badge/jooby-assets-csslint-brightgreen.svg)](http://jooby.org/doc/assets-csslint) # csslint @@ -13,7 +13,7 @@ Make sure you've already set up the [assets module](https://github.com/jooby-pro org.jooby jooby-assets-csslint - 1.5.0 + 1.6.6 provided ``` diff --git a/modules/jooby-assets-csslint/pom.xml b/modules/jooby-assets-csslint/pom.xml index 4d8c6d4644..75be7fb6ea 100644 --- a/modules/jooby-assets-csslint/pom.xml +++ b/modules/jooby-assets-csslint/pom.xml @@ -5,7 +5,7 @@ org.jooby modules - 1.5.1-SNAPSHOT + 1.6.9 4.0.0 diff --git a/modules/jooby-assets-j2v8/pom.xml b/modules/jooby-assets-j2v8/pom.xml index e07ac2505c..bbf98724b9 100644 --- a/modules/jooby-assets-j2v8/pom.xml +++ b/modules/jooby-assets-j2v8/pom.xml @@ -5,7 +5,7 @@ org.jooby modules - 1.5.1-SNAPSHOT + 1.6.9 4.0.0 diff --git a/modules/jooby-assets-jscs/README.md b/modules/jooby-assets-jscs/README.md index eb36431d87..1a6dccc3ff 100644 --- a/modules/jooby-assets-jscs/README.md +++ b/modules/jooby-assets-jscs/README.md @@ -1,5 +1,5 @@ -[![Maven Central](https://maven-badges.herokuapp.com/maven-central/org.jooby/jooby-assets-jscs/badge.svg)](https://maven-badges.herokuapp.com/maven-central/org.jooby/jooby-assets-jscs) -[![javadoc](https://javadoc.io/badge/org.jooby/jooby-assets-jscs.svg)](https://javadoc.io/doc/org.jooby/jooby-assets-jscs/1.5.0) +[![Maven](https://img.shields.io/maven-metadata/v/http/central.maven.org/maven2/org/jooby/jooby-assets-jscs/maven-metadata.xml.svg)](http://mvnrepository.com/artifact/org.jooby/jooby-assets-jscs/1.6.6) +[![javadoc](https://javadoc.io/badge/org.jooby/jooby-assets-jscs.svg)](https://javadoc.io/doc/org.jooby/jooby-assets-jscs/1.6.6) [![jooby-assets-jscs website](https://img.shields.io/badge/jooby-assets-jscs-brightgreen.svg)](http://jooby.org/doc/assets-jscs) # jscs @@ -13,7 +13,7 @@ Make sure you've already set up the [assets module](https://github.com/jooby-pro org.jooby jooby-assets-jscs - 1.5.0 + 1.6.6 provided ``` diff --git a/modules/jooby-assets-jscs/pom.xml b/modules/jooby-assets-jscs/pom.xml index 73e2dd66c5..077f472790 100644 --- a/modules/jooby-assets-jscs/pom.xml +++ b/modules/jooby-assets-jscs/pom.xml @@ -5,7 +5,7 @@ org.jooby modules - 1.5.1-SNAPSHOT + 1.6.9 4.0.0 diff --git a/modules/jooby-assets-jshint/README.md b/modules/jooby-assets-jshint/README.md index 4031699da2..619aff0373 100644 --- a/modules/jooby-assets-jshint/README.md +++ b/modules/jooby-assets-jshint/README.md @@ -1,5 +1,5 @@ -[![Maven Central](https://maven-badges.herokuapp.com/maven-central/org.jooby/jooby-assets-jshint/badge.svg)](https://maven-badges.herokuapp.com/maven-central/org.jooby/jooby-assets-jshint) -[![javadoc](https://javadoc.io/badge/org.jooby/jooby-assets-jshint.svg)](https://javadoc.io/doc/org.jooby/jooby-assets-jshint/1.5.0) +[![Maven](https://img.shields.io/maven-metadata/v/http/central.maven.org/maven2/org/jooby/jooby-assets-jshint/maven-metadata.xml.svg)](http://mvnrepository.com/artifact/org.jooby/jooby-assets-jshint/1.6.6) +[![javadoc](https://javadoc.io/badge/org.jooby/jooby-assets-jshint.svg)](https://javadoc.io/doc/org.jooby/jooby-assets-jshint/1.6.6) [![jooby-assets-jshint website](https://img.shields.io/badge/jooby-assets-jshint-brightgreen.svg)](http://jooby.org/doc/assets-jshint) # jshint @@ -13,7 +13,7 @@ Make sure you've already set up the [assets module](https://github.com/jooby-pro org.jooby jooby-assets-jshint - 1.5.0 + 1.6.6 provided ``` diff --git a/modules/jooby-assets-jshint/pom.xml b/modules/jooby-assets-jshint/pom.xml index 66800079c4..c2127bbca9 100644 --- a/modules/jooby-assets-jshint/pom.xml +++ b/modules/jooby-assets-jshint/pom.xml @@ -5,7 +5,7 @@ org.jooby modules - 1.5.1-SNAPSHOT + 1.6.9 4.0.0 diff --git a/modules/jooby-assets-less/README.md b/modules/jooby-assets-less/README.md index d437ed3754..bfc1dd2e18 100644 --- a/modules/jooby-assets-less/README.md +++ b/modules/jooby-assets-less/README.md @@ -1,5 +1,5 @@ -[![Maven Central](https://maven-badges.herokuapp.com/maven-central/org.jooby/jooby-assets-less/badge.svg)](https://maven-badges.herokuapp.com/maven-central/org.jooby/jooby-assets-less) -[![javadoc](https://javadoc.io/badge/org.jooby/jooby-assets-less.svg)](https://javadoc.io/doc/org.jooby/jooby-assets-less/1.5.0) +[![Maven](https://img.shields.io/maven-metadata/v/http/central.maven.org/maven2/org/jooby/jooby-assets-less/maven-metadata.xml.svg)](http://mvnrepository.com/artifact/org.jooby/jooby-assets-less/1.6.6) +[![javadoc](https://javadoc.io/badge/org.jooby/jooby-assets-less.svg)](https://javadoc.io/doc/org.jooby/jooby-assets-less/1.6.6) [![jooby-assets-less website](https://img.shields.io/badge/jooby-assets-less-brightgreen.svg)](http://jooby.org/doc/assets-less) # less @@ -13,7 +13,7 @@ Make sure you've already set up the [assets module](https://github.com/jooby-pro org.jooby jooby-assets-less - 1.5.0 + 1.6.6 provided ``` diff --git a/modules/jooby-assets-less/pom.xml b/modules/jooby-assets-less/pom.xml index 8ae78daeef..13c4fe8afe 100644 --- a/modules/jooby-assets-less/pom.xml +++ b/modules/jooby-assets-less/pom.xml @@ -5,7 +5,7 @@ org.jooby modules - 1.5.1-SNAPSHOT + 1.6.9 4.0.0 diff --git a/modules/jooby-assets-less4j/README.md b/modules/jooby-assets-less4j/README.md index f710980658..9d3adda33f 100644 --- a/modules/jooby-assets-less4j/README.md +++ b/modules/jooby-assets-less4j/README.md @@ -1,5 +1,5 @@ -[![Maven Central](https://maven-badges.herokuapp.com/maven-central/org.jooby/jooby-assets-less4j/badge.svg)](https://maven-badges.herokuapp.com/maven-central/org.jooby/jooby-assets-less4j) -[![javadoc](https://javadoc.io/badge/org.jooby/jooby-assets-less4j.svg)](https://javadoc.io/doc/org.jooby/jooby-assets-less4j/1.5.0) +[![Maven](https://img.shields.io/maven-metadata/v/http/central.maven.org/maven2/org/jooby/jooby-assets-less4j/maven-metadata.xml.svg)](http://mvnrepository.com/artifact/org.jooby/jooby-assets-less4j/1.6.6) +[![javadoc](https://javadoc.io/badge/org.jooby/jooby-assets-less4j.svg)](https://javadoc.io/doc/org.jooby/jooby-assets-less4j/1.6.6) [![jooby-assets-less4j website](https://img.shields.io/badge/jooby-assets-less4j-brightgreen.svg)](http://jooby.org/doc/assets-less4j) # less4j @@ -13,7 +13,7 @@ Make sure you've already set up the [assets module](https://github.com/jooby-pro org.jooby jooby-assets-less4j - 1.5.0 + 1.6.6 provided ``` diff --git a/modules/jooby-assets-less4j/pom.xml b/modules/jooby-assets-less4j/pom.xml index ad1c4b6dad..aec61b7e8e 100644 --- a/modules/jooby-assets-less4j/pom.xml +++ b/modules/jooby-assets-less4j/pom.xml @@ -5,7 +5,7 @@ org.jooby modules - 1.5.1-SNAPSHOT + 1.6.9 4.0.0 diff --git a/modules/jooby-assets-ng-annotate/README.md b/modules/jooby-assets-ng-annotate/README.md index d445bf92e7..5df9a092dd 100644 --- a/modules/jooby-assets-ng-annotate/README.md +++ b/modules/jooby-assets-ng-annotate/README.md @@ -1,5 +1,5 @@ -[![Maven Central](https://maven-badges.herokuapp.com/maven-central/org.jooby/jooby-assets-ng-annotate/badge.svg)](https://maven-badges.herokuapp.com/maven-central/org.jooby/jooby-assets-ng-annotate) -[![javadoc](https://javadoc.io/badge/org.jooby/jooby-assets-ng-annotate.svg)](https://javadoc.io/doc/org.jooby/jooby-assets-ng-annotate/1.5.0) +[![Maven](https://img.shields.io/maven-metadata/v/http/central.maven.org/maven2/org/jooby/jooby-assets-ng-annotate/maven-metadata.xml.svg)](http://mvnrepository.com/artifact/org.jooby/jooby-assets-ng-annotate/1.6.6) +[![javadoc](https://javadoc.io/badge/org.jooby/jooby-assets-ng-annotate.svg)](https://javadoc.io/doc/org.jooby/jooby-assets-ng-annotate/1.6.6) [![jooby-assets-ng-annotate website](https://img.shields.io/badge/jooby-assets-ng-annotate-brightgreen.svg)](http://jooby.org/doc/assets-ng-annotate) # ng-annotate @@ -13,7 +13,7 @@ Make sure you've already set up the [assets module](https://github.com/jooby-pro org.jooby jooby-assets-ng-annotate - 1.5.0 + 1.6.6 provided ``` diff --git a/modules/jooby-assets-ng-annotate/pom.xml b/modules/jooby-assets-ng-annotate/pom.xml index f7d3991f3f..b0753c845a 100644 --- a/modules/jooby-assets-ng-annotate/pom.xml +++ b/modules/jooby-assets-ng-annotate/pom.xml @@ -5,7 +5,7 @@ org.jooby modules - 1.5.1-SNAPSHOT + 1.6.9 4.0.0 diff --git a/modules/jooby-assets-nodejs/pom.xml b/modules/jooby-assets-nodejs/pom.xml index efd0d65913..4aa560e10c 100644 --- a/modules/jooby-assets-nodejs/pom.xml +++ b/modules/jooby-assets-nodejs/pom.xml @@ -5,7 +5,7 @@ org.jooby modules - 1.5.1-SNAPSHOT + 1.6.9 4.0.0 diff --git a/modules/jooby-assets-requirejs/README.md b/modules/jooby-assets-requirejs/README.md index d404b4491b..6e27f8a7a0 100644 --- a/modules/jooby-assets-requirejs/README.md +++ b/modules/jooby-assets-requirejs/README.md @@ -1,5 +1,5 @@ -[![Maven Central](https://maven-badges.herokuapp.com/maven-central/org.jooby/jooby-assets-requirejs/badge.svg)](https://maven-badges.herokuapp.com/maven-central/org.jooby/jooby-assets-requirejs) -[![javadoc](https://javadoc.io/badge/org.jooby/jooby-assets-requirejs.svg)](https://javadoc.io/doc/org.jooby/jooby-assets-requirejs/1.5.0) +[![Maven](https://img.shields.io/maven-metadata/v/http/central.maven.org/maven2/org/jooby/jooby-assets-requirejs/maven-metadata.xml.svg)](http://mvnrepository.com/artifact/org.jooby/jooby-assets-requirejs/1.6.6) +[![javadoc](https://javadoc.io/badge/org.jooby/jooby-assets-requirejs.svg)](https://javadoc.io/doc/org.jooby/jooby-assets-requirejs/1.6.6) [![jooby-assets-requirejs website](https://img.shields.io/badge/jooby-assets-requirejs-brightgreen.svg)](http://jooby.org/doc/assets-requirejs) # rjs @@ -13,7 +13,7 @@ Make sure you've already set up the [assets module](https://github.com/jooby-pro org.jooby jooby-assets-requirejs - 1.5.0 + 1.6.6 provided ``` diff --git a/modules/jooby-assets-requirejs/pom.xml b/modules/jooby-assets-requirejs/pom.xml index a03f19abc4..711ecdd09f 100644 --- a/modules/jooby-assets-requirejs/pom.xml +++ b/modules/jooby-assets-requirejs/pom.xml @@ -5,7 +5,7 @@ org.jooby modules - 1.5.1-SNAPSHOT + 1.6.9 4.0.0 diff --git a/modules/jooby-assets-rollup/README.md b/modules/jooby-assets-rollup/README.md index ce29e76d24..76da6a1471 100644 --- a/modules/jooby-assets-rollup/README.md +++ b/modules/jooby-assets-rollup/README.md @@ -1,5 +1,5 @@ -[![Maven Central](https://maven-badges.herokuapp.com/maven-central/org.jooby/jooby-assets-rollup/badge.svg)](https://maven-badges.herokuapp.com/maven-central/org.jooby/jooby-assets-rollup) -[![javadoc](https://javadoc.io/badge/org.jooby/jooby-assets-rollup.svg)](https://javadoc.io/doc/org.jooby/jooby-assets-rollup/1.5.0) +[![Maven](https://img.shields.io/maven-metadata/v/http/central.maven.org/maven2/org/jooby/jooby-assets-rollup/maven-metadata.xml.svg)](http://mvnrepository.com/artifact/org.jooby/jooby-assets-rollup/1.6.6) +[![javadoc](https://javadoc.io/badge/org.jooby/jooby-assets-rollup.svg)](https://javadoc.io/doc/org.jooby/jooby-assets-rollup/1.6.6) [![jooby-assets-rollup website](https://img.shields.io/badge/jooby-assets-rollup-brightgreen.svg)](http://jooby.org/doc/assets-rollup) # rollup.js @@ -13,7 +13,7 @@ Make sure you've already set up the [assets module](https://github.com/jooby-pro org.jooby jooby-rollup.js - 1.5.0 + 1.6.6 provided ``` diff --git a/modules/jooby-assets-rollup/pom.xml b/modules/jooby-assets-rollup/pom.xml index 23311979eb..171b41939f 100644 --- a/modules/jooby-assets-rollup/pom.xml +++ b/modules/jooby-assets-rollup/pom.xml @@ -5,7 +5,7 @@ org.jooby modules - 1.5.1-SNAPSHOT + 1.6.9 4.0.0 diff --git a/modules/jooby-assets-sass/README.md b/modules/jooby-assets-sass/README.md index 8478250cb8..109ef7257f 100644 --- a/modules/jooby-assets-sass/README.md +++ b/modules/jooby-assets-sass/README.md @@ -1,5 +1,5 @@ -[![Maven Central](https://maven-badges.herokuapp.com/maven-central/org.jooby/jooby-assets-sass/badge.svg)](https://maven-badges.herokuapp.com/maven-central/org.jooby/jooby-assets-sass) -[![javadoc](https://javadoc.io/badge/org.jooby/jooby-assets-sass.svg)](https://javadoc.io/doc/org.jooby/jooby-assets-sass/1.5.0) +[![Maven](https://img.shields.io/maven-metadata/v/http/central.maven.org/maven2/org/jooby/jooby-assets-sass/maven-metadata.xml.svg)](http://mvnrepository.com/artifact/org.jooby/jooby-assets-sass/1.6.6) +[![javadoc](https://javadoc.io/badge/org.jooby/jooby-assets-sass.svg)](https://javadoc.io/doc/org.jooby/jooby-assets-sass/1.6.6) [![jooby-assets-sass website](https://img.shields.io/badge/jooby-assets-sass-brightgreen.svg)](http://jooby.org/doc/assets-sass) # sass @@ -13,7 +13,7 @@ org.jooby jooby-assets-sass - 1.5.0 + 1.6.6 provided ``` diff --git a/modules/jooby-assets-sass/pom.xml b/modules/jooby-assets-sass/pom.xml index 8d75e73e5c..6a28141e8a 100644 --- a/modules/jooby-assets-sass/pom.xml +++ b/modules/jooby-assets-sass/pom.xml @@ -5,7 +5,7 @@ org.jooby modules - 1.5.1-SNAPSHOT + 1.6.9 4.0.0 diff --git a/modules/jooby-assets-sass/src/test/java/org/jooby/assets/SassTest.java b/modules/jooby-assets-sass/src/test/java/org/jooby/assets/SassTest.java index 5223745d43..15bae91a87 100644 --- a/modules/jooby-assets-sass/src/test/java/org/jooby/assets/SassTest.java +++ b/modules/jooby-assets-sass/src/test/java/org/jooby/assets/SassTest.java @@ -1,8 +1,11 @@ package org.jooby.assets; +import static org.hamcrest.CoreMatchers.startsWith; +import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; +import org.hamcrest.core.StringStartsWith; import org.junit.Test; import com.typesafe.config.ConfigFactory; @@ -204,14 +207,14 @@ public void inlineSourceMap() throws Exception { " color: $primary-color;\n" + "}\n", ConfigFactory.empty()); - assertTrue(output.startsWith(".foo {\n" + - " color: #fff; }\n" + - "\n" + - "body {\n" + - " font: 100% Helvetica, sans-serif;\n" + - " color: #333; }\n" + - "\n" + - "/*# sourceMappingURL=data:application/json;base64,ewoJInZlcnNpb24iOiAzLAoJImZpbGUiOiAiLi4vLi4v")); + assertThat(output, startsWith(".foo {\n" + + " color: #fff; }\n" + + "\n" + + "body {\n" + + " font: 100% Helvetica, sans-serif;\n" + + " color: #333; }\n" + + "\n" + + "/*# sourceMappingURL=data:application/json;base64,ewoJInZlcnNpb24iOiAzLAoJImZpbGUiOiAiL")); // include up to "file": " } @Test diff --git a/modules/jooby-assets-svg-sprites/README.md b/modules/jooby-assets-svg-sprites/README.md index b70ffa082d..765ee9f46a 100644 --- a/modules/jooby-assets-svg-sprites/README.md +++ b/modules/jooby-assets-svg-sprites/README.md @@ -1,5 +1,5 @@ -[![Maven Central](https://maven-badges.herokuapp.com/maven-central/org.jooby/jooby-assets-svg-sprites/badge.svg)](https://maven-badges.herokuapp.com/maven-central/org.jooby/jooby-assets-svg-sprites) -[![javadoc](https://javadoc.io/badge/org.jooby/jooby-assets-svg-sprites.svg)](https://javadoc.io/doc/org.jooby/jooby-assets-svg-sprites/1.5.0) +[![Maven](https://img.shields.io/maven-metadata/v/http/central.maven.org/maven2/org/jooby/jooby-assets-svg-sprites/maven-metadata.xml.svg)](http://mvnrepository.com/artifact/org.jooby/jooby-assets-svg-sprites/1.6.6) +[![javadoc](https://javadoc.io/badge/org.jooby/jooby-assets-svg-sprites.svg)](https://javadoc.io/doc/org.jooby/jooby-assets-svg-sprites/1.6.6) [![jooby-assets-svg-sprites website](https://img.shields.io/badge/jooby-assets-svg-sprites-brightgreen.svg)](http://jooby.org/doc/assets-svg-sprites) # svg-sprites @@ -13,7 +13,7 @@ Make sure you've already set up the [assets module](https://github.com/jooby-pro org.jooby jooby-assets-svg-sprites - 1.5.0 + 1.6.6 provided ``` diff --git a/modules/jooby-assets-svg-sprites/pom.xml b/modules/jooby-assets-svg-sprites/pom.xml index a703117158..5b8f70dc71 100644 --- a/modules/jooby-assets-svg-sprites/pom.xml +++ b/modules/jooby-assets-svg-sprites/pom.xml @@ -5,7 +5,7 @@ org.jooby modules - 1.5.1-SNAPSHOT + 1.6.9 4.0.0 diff --git a/modules/jooby-assets-svg-sprites/src/test/java/org/jooby/assets/SvgSpritesFileSetTest.java b/modules/jooby-assets-svg-sprites/src/test/java/org/jooby/assets/SvgSpritesFileSetTest.java index 57e0c079c4..e8a1779507 100644 --- a/modules/jooby-assets-svg-sprites/src/test/java/org/jooby/assets/SvgSpritesFileSetTest.java +++ b/modules/jooby-assets-svg-sprites/src/test/java/org/jooby/assets/SvgSpritesFileSetTest.java @@ -17,7 +17,7 @@ public void requireSpriteElementPath() throws Exception { @Test public void cssPath() throws Exception { - assertEquals(Paths.get("target", "css", "sprite.css").toString(), + assertEquals(Paths.get("target", "css").toString() + "/sprite.css", new SvgSprites() .set("spritePath", Paths.get("target", "css").toString()) .cssPath()); @@ -30,7 +30,7 @@ public void cssPath() throws Exception { @Test public void spritePath() throws Exception { - assertEquals(Paths.get("target", "css", "sprite.svg").toString(), + assertEquals(Paths.get("target", "css").toString() + "/sprite.svg", new SvgSprites() .set("spritePath", Paths.get("target", "css").toString()) .spritePath()); @@ -43,7 +43,7 @@ public void spritePath() throws Exception { @Test public void spritePrefix() throws Exception { - assertEquals(Paths.get("target", "css", "p-sprite.svg").toString(), + assertEquals(Paths.get("target", "css").toString() + "/p-sprite.svg", new SvgSprites() .set("prefix", "p") .set("spritePath", Paths.get("target", "css").toString()) @@ -58,14 +58,14 @@ public void spritePrefix() throws Exception { @Test public void spriteName() throws Exception { - assertEquals(Paths.get("target", "css", "p-n-sprite.svg").toString(), + assertEquals(Paths.get("target", "css").toString() + "/p-n-sprite.svg", new SvgSprites() .set("prefix", "p") .set("name", "n") .set("spritePath", Paths.get("target", "css").toString()) .spritePath()); - assertEquals(Paths.get("target", "css", "n-sprite.svg").toString(), + assertEquals(Paths.get("target", "css").toString() + "/n-sprite.svg", new SvgSprites() .set("name", "n") .set("spritePath", Paths.get("target", "css").toString()) @@ -74,7 +74,7 @@ public void spriteName() throws Exception { @Test public void cssPrefix() throws Exception { - assertEquals(Paths.get("target", "css", "p-sprite.css").toString(), + assertEquals(Paths.get("target", "css").toString() + "/p-sprite.css", new SvgSprites() .set("prefix", "p") .set("spritePath", Paths.get("target", "css").toString()) diff --git a/modules/jooby-assets-svg-symbol/README.md b/modules/jooby-assets-svg-symbol/README.md index 2a2a33c7ac..434c580bbb 100644 --- a/modules/jooby-assets-svg-symbol/README.md +++ b/modules/jooby-assets-svg-symbol/README.md @@ -1,5 +1,5 @@ -[![Maven Central](https://maven-badges.herokuapp.com/maven-central/org.jooby/jooby-assets-svg-symbol/badge.svg)](https://maven-badges.herokuapp.com/maven-central/org.jooby/jooby-assets-svg-symbol) -[![javadoc](https://javadoc.io/badge/org.jooby/jooby-assets-svg-symbol.svg)](https://javadoc.io/doc/org.jooby/jooby-assets-svg-symbol/1.5.0) +[![Maven](https://img.shields.io/maven-metadata/v/http/central.maven.org/maven2/org/jooby/jooby-assets-svg-symbol/maven-metadata.xml.svg)](http://mvnrepository.com/artifact/org.jooby/jooby-assets-svg-symbol/1.6.6) +[![javadoc](https://javadoc.io/badge/org.jooby/jooby-assets-svg-symbol.svg)](https://javadoc.io/doc/org.jooby/jooby-assets-svg-symbol/1.6.6) [![jooby-assets-svg-symbol website](https://img.shields.io/badge/jooby-assets-svg-symbol-brightgreen.svg)](http://jooby.org/doc/assets-svg-symbol) # svg-symbol @@ -13,7 +13,7 @@ Make sure you've already set up the [assets module](https://github.com/jooby-pro org.jooby jooby-assets-svg-symbol - 1.5.0 + 1.6.6 provided ``` diff --git a/modules/jooby-assets-svg-symbol/pom.xml b/modules/jooby-assets-svg-symbol/pom.xml index bff94b4b57..737cc57a66 100644 --- a/modules/jooby-assets-svg-symbol/pom.xml +++ b/modules/jooby-assets-svg-symbol/pom.xml @@ -5,7 +5,7 @@ org.jooby modules - 1.5.1-SNAPSHOT + 1.6.9 4.0.0 diff --git a/modules/jooby-assets-uglify/README.md b/modules/jooby-assets-uglify/README.md index ba90ce093d..f5309ee6e9 100644 --- a/modules/jooby-assets-uglify/README.md +++ b/modules/jooby-assets-uglify/README.md @@ -1,5 +1,5 @@ -[![Maven Central](https://maven-badges.herokuapp.com/maven-central/org.jooby/jooby-assets-uglify/badge.svg)](https://maven-badges.herokuapp.com/maven-central/org.jooby/jooby-assets-uglify) -[![javadoc](https://javadoc.io/badge/org.jooby/jooby-assets-uglify.svg)](https://javadoc.io/doc/org.jooby/jooby-assets-uglify/1.5.0) +[![Maven](https://img.shields.io/maven-metadata/v/http/central.maven.org/maven2/org/jooby/jooby-assets-uglify/maven-metadata.xml.svg)](http://mvnrepository.com/artifact/org.jooby/jooby-assets-uglify/1.6.6) +[![javadoc](https://javadoc.io/badge/org.jooby/jooby-assets-uglify.svg)](https://javadoc.io/doc/org.jooby/jooby-assets-uglify/1.6.6) [![jooby-assets-uglify website](https://img.shields.io/badge/jooby-assets-uglify-brightgreen.svg)](http://jooby.org/doc/assets-uglify) # uglify @@ -13,7 +13,7 @@ Make sure you've already set up the [assets module](https://github.com/jooby-pro org.jooby jooby-assets-uglify - 1.5.0 + 1.6.6 provided ``` diff --git a/modules/jooby-assets-uglify/pom.xml b/modules/jooby-assets-uglify/pom.xml index 33941f9d91..cf5f3c95ca 100644 --- a/modules/jooby-assets-uglify/pom.xml +++ b/modules/jooby-assets-uglify/pom.xml @@ -5,7 +5,7 @@ org.jooby modules - 1.5.1-SNAPSHOT + 1.6.9 4.0.0 diff --git a/modules/jooby-assets-yui-compressor/README.md b/modules/jooby-assets-yui-compressor/README.md index f8fbaa13d0..df88377ce4 100644 --- a/modules/jooby-assets-yui-compressor/README.md +++ b/modules/jooby-assets-yui-compressor/README.md @@ -1,5 +1,5 @@ -[![Maven Central](https://maven-badges.herokuapp.com/maven-central/org.jooby/jooby-assets-yui-compressor/badge.svg)](https://maven-badges.herokuapp.com/maven-central/org.jooby/jooby-assets-yui-compressor) -[![javadoc](https://javadoc.io/badge/org.jooby/jooby-assets-yui-compressor.svg)](https://javadoc.io/doc/org.jooby/jooby-assets-yui-compressor/1.5.0) +[![Maven](https://img.shields.io/maven-metadata/v/http/central.maven.org/maven2/org/jooby/jooby-assets-yui-compressor/maven-metadata.xml.svg)](http://mvnrepository.com/artifact/org.jooby/jooby-assets-yui-compressor/1.6.6) +[![javadoc](https://javadoc.io/badge/org.jooby/jooby-assets-yui-compressor.svg)](https://javadoc.io/doc/org.jooby/jooby-assets-yui-compressor/1.6.6) [![jooby-assets-yui-compressor website](https://img.shields.io/badge/jooby-assets-yui-compressor-brightgreen.svg)](http://jooby.org/doc/assets-yui-compressor) # yui-css @@ -13,7 +13,7 @@ Make sure you've already set up the [assets module](https://github.com/jooby-pro org.jooby jooby-assets-yui-compressor - 1.5.0 + 1.6.6 provided ``` diff --git a/modules/jooby-assets-yui-compressor/pom.xml b/modules/jooby-assets-yui-compressor/pom.xml index 4b6eb787ee..d599f09959 100644 --- a/modules/jooby-assets-yui-compressor/pom.xml +++ b/modules/jooby-assets-yui-compressor/pom.xml @@ -5,7 +5,7 @@ org.jooby modules - 1.5.1-SNAPSHOT + 1.6.9 4.0.0 diff --git a/modules/jooby-assets/README.md b/modules/jooby-assets/README.md index 5f8476971d..24f51c1012 100644 --- a/modules/jooby-assets/README.md +++ b/modules/jooby-assets/README.md @@ -1,5 +1,5 @@ -[![Maven Central](https://maven-badges.herokuapp.com/maven-central/org.jooby/jooby-assets/badge.svg)](https://maven-badges.herokuapp.com/maven-central/org.jooby/jooby-assets) -[![javadoc](https://javadoc.io/badge/org.jooby/jooby-assets.svg)](https://javadoc.io/doc/org.jooby/jooby-assets/1.5.0) +[![Maven](https://img.shields.io/maven-metadata/v/http/central.maven.org/maven2/org/jooby/jooby-assets/maven-metadata.xml.svg)](http://mvnrepository.com/artifact/org.jooby/jooby-assets/1.6.6) +[![javadoc](https://javadoc.io/badge/org.jooby/jooby-assets.svg)](https://javadoc.io/doc/org.jooby/jooby-assets/1.6.6) [![jooby-assets website](https://img.shields.io/badge/jooby-assets-brightgreen.svg)](http://jooby.org/doc/assets) # assets @@ -13,7 +13,7 @@ A variety of processors are available: ([jshint](https://github.com/jooby-projec org.jooby jooby-assets - 1.5.0 + 1.6.6 ``` diff --git a/modules/jooby-assets/pom.xml b/modules/jooby-assets/pom.xml index b11822538c..2ca0576946 100644 --- a/modules/jooby-assets/pom.xml +++ b/modules/jooby-assets/pom.xml @@ -5,7 +5,7 @@ org.jooby modules - 1.5.1-SNAPSHOT + 1.6.9 4.0.0 diff --git a/modules/jooby-assets/src/main/java/org/jooby/assets/Assets.java b/modules/jooby-assets/src/main/java/org/jooby/assets/Assets.java index c1e25326d0..e51b6a340a 100644 --- a/modules/jooby-assets/src/main/java/org/jooby/assets/Assets.java +++ b/modules/jooby-assets/src/main/java/org/jooby/assets/Assets.java @@ -209,6 +209,7 @@ import com.typesafe.config.ConfigFactory; import org.jooby.Env; import org.jooby.Jooby; +import org.jooby.Route; import org.jooby.Router; import org.jooby.handlers.AssetHandler; import org.jooby.internal.assets.AssetVars; @@ -219,6 +220,8 @@ import org.slf4j.LoggerFactory; import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; import java.nio.file.Path; import java.nio.file.Paths; import java.util.List; @@ -568,10 +571,10 @@ public void configure(final Env env, final Config config, final Binder binder) t return ConfigFactory.parseResources(getClass(), "assets.conf"); } - private Config conf(final boolean dev, final ClassLoader loader, final Config conf) { - final Config[] confs; + private Config conf(final boolean dev, final ClassLoader loader, final Config conf) throws + IOException { if (!dev) { - confs = new Config[]{ + Config[] confs = { ConfigFactory.parseResources(loader, "assets." + conf.getString("application.env").toLowerCase() + ".conf"), ConfigFactory.parseResources(loader, "assets.dist.conf"), @@ -582,6 +585,9 @@ private Config conf(final boolean dev, final ClassLoader loader, final Config co } } } + if (loader.getResource("assets.conf") == null) { + throw new FileNotFoundException("assets.conf"); + } return ConfigFactory.parseResources(loader, "assets.conf").withFallback(conf).resolve(); } diff --git a/modules/jooby-assets/src/main/java/org/jooby/internal/assets/Watcher.java b/modules/jooby-assets/src/main/java/org/jooby/internal/assets/Watcher.java index 900ab0b886..58a188c339 100644 --- a/modules/jooby-assets/src/main/java/org/jooby/internal/assets/Watcher.java +++ b/modules/jooby-assets/src/main/java/org/jooby/internal/assets/Watcher.java @@ -203,12 +203,13 @@ */ package org.jooby.internal.assets; -import com.sun.nio.file.SensitivityWatchEventModifier; import static java.nio.file.LinkOption.NOFOLLOW_LINKS; import static java.nio.file.StandardWatchEventKinds.ENTRY_CREATE; import static java.nio.file.StandardWatchEventKinds.ENTRY_DELETE; import static java.nio.file.StandardWatchEventKinds.ENTRY_MODIFY; import static java.nio.file.StandardWatchEventKinds.OVERFLOW; + +import org.jooby.spi.WatchEventModifier; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -232,7 +233,7 @@ class Watcher { - private static final WatchEvent.Modifier HIGH = SensitivityWatchEventModifier.HIGH; + private static final WatchEvent.Modifier HIGH = WatchEventModifier.modifier("HIGH"); /** The logging system. */ private final Logger log = LoggerFactory.getLogger(getClass()); private final WatchService watcher; diff --git a/modules/jooby-assets/src/test/java/org/jooby/assets/AssetCompilerTest.java b/modules/jooby-assets/src/test/java/org/jooby/assets/AssetCompilerTest.java index 2e24ef5382..a0fda34c8a 100644 --- a/modules/jooby-assets/src/test/java/org/jooby/assets/AssetCompilerTest.java +++ b/modules/jooby-assets/src/test/java/org/jooby/assets/AssetCompilerTest.java @@ -81,7 +81,7 @@ public void summary() throws Exception { File dir = Paths.get("target", "summary").toFile(); Map> files = compiler.build("dev", dir); - + String summary = compiler.summary(files, dir.toPath(), "dev", 1000, "Foo: bar").replaceAll("\\\\","/"); assertEquals("Summary:\n" + "Pipeline: []\n" + "Time: 1s\n" @@ -92,7 +92,7 @@ public void summary() throws Exception { + " assets/home.css 8b\n" + " assets/base.js 19b\n" + " assets/home.js 19b\n", - compiler.summary(files, dir.toPath(), "dev", 1000, "Foo: bar")); + summary); } @Test diff --git a/modules/jooby-assets/src/test/resources/assets.conf b/modules/jooby-assets/src/test/resources/assets.conf new file mode 100644 index 0000000000..fa81adaff6 --- /dev/null +++ b/modules/jooby-assets/src/test/resources/assets.conf @@ -0,0 +1 @@ +# empty file diff --git a/modules/jooby-aws/README.md b/modules/jooby-aws/README.md index bf703d8654..233aaf858e 100644 --- a/modules/jooby-aws/README.md +++ b/modules/jooby-aws/README.md @@ -1,5 +1,5 @@ -[![Maven Central](https://maven-badges.herokuapp.com/maven-central/org.jooby/jooby-aws/badge.svg)](https://maven-badges.herokuapp.com/maven-central/org.jooby/jooby-aws) -[![javadoc](https://javadoc.io/badge/org.jooby/jooby-aws.svg)](https://javadoc.io/doc/org.jooby/jooby-aws/1.5.0) +[![Maven](https://img.shields.io/maven-metadata/v/http/central.maven.org/maven2/org/jooby/jooby-aws/maven-metadata.xml.svg)](http://mvnrepository.com/artifact/org.jooby/jooby-aws/1.6.6) +[![javadoc](https://javadoc.io/badge/org.jooby/jooby-aws.svg)](https://javadoc.io/doc/org.jooby/jooby-aws/1.6.6) [![jooby-aws website](https://img.shields.io/badge/jooby-aws-brightgreen.svg)](http://jooby.org/doc/aws) # aws @@ -15,7 +15,7 @@ Small utility module that exports ```AmazonWebServiceClient``` services. org.jooby jooby-aws - 1.5.0 + 1.6.6 ``` diff --git a/modules/jooby-aws/pom.xml b/modules/jooby-aws/pom.xml index efd02bacb8..207d69f595 100644 --- a/modules/jooby-aws/pom.xml +++ b/modules/jooby-aws/pom.xml @@ -5,7 +5,7 @@ org.jooby modules - 1.5.1-SNAPSHOT + 1.6.9 4.0.0 diff --git a/modules/jooby-banner/README.md b/modules/jooby-banner/README.md index 1efd4dc7d3..7e983048e1 100644 --- a/modules/jooby-banner/README.md +++ b/modules/jooby-banner/README.md @@ -1,5 +1,5 @@ -[![Maven Central](https://maven-badges.herokuapp.com/maven-central/org.jooby/jooby-banner/badge.svg)](https://maven-badges.herokuapp.com/maven-central/org.jooby/jooby-banner) -[![javadoc](https://javadoc.io/badge/org.jooby/jooby-banner.svg)](https://javadoc.io/doc/org.jooby/jooby-banner/1.5.0) +[![Maven](https://img.shields.io/maven-metadata/v/http/central.maven.org/maven2/org/jooby/jooby-banner/maven-metadata.xml.svg)](http://mvnrepository.com/artifact/org.jooby/jooby-banner/1.6.6) +[![javadoc](https://javadoc.io/badge/org.jooby/jooby-banner.svg)](https://javadoc.io/doc/org.jooby/jooby-banner/1.6.6) [![jooby-banner website](https://img.shields.io/badge/jooby-banner-brightgreen.svg)](http://jooby.org/doc/banner) # banner @@ -11,7 +11,7 @@ Prints out an ASCII art banner on startup using org.jooby jooby-caffeine - 1.5.0 + 1.6.6 ``` diff --git a/modules/jooby-caffeine/pom.xml b/modules/jooby-caffeine/pom.xml index f601fe1543..569aad26ed 100644 --- a/modules/jooby-caffeine/pom.xml +++ b/modules/jooby-caffeine/pom.xml @@ -5,7 +5,7 @@ org.jooby modules - 1.5.1-SNAPSHOT + 1.6.9 4.0.0 diff --git a/modules/jooby-camel/README.md b/modules/jooby-camel/README.md index 255e3048f2..c9033a8097 100644 --- a/modules/jooby-camel/README.md +++ b/modules/jooby-camel/README.md @@ -1,5 +1,5 @@ -[![Maven Central](https://maven-badges.herokuapp.com/maven-central/org.jooby/jooby-camel/badge.svg)](https://maven-badges.herokuapp.com/maven-central/org.jooby/jooby-camel) -[![javadoc](https://javadoc.io/badge/org.jooby/jooby-camel.svg)](https://javadoc.io/doc/org.jooby/jooby-camel/1.5.0) +[![Maven](https://img.shields.io/maven-metadata/v/http/central.maven.org/maven2/org/jooby/jooby-camel/maven-metadata.xml.svg)](http://mvnrepository.com/artifact/org.jooby/jooby-camel/1.6.6) +[![javadoc](https://javadoc.io/badge/org.jooby/jooby-camel.svg)](https://javadoc.io/doc/org.jooby/jooby-camel/1.6.6) [![jooby-camel website](https://img.shields.io/badge/jooby-camel-brightgreen.svg)](http://jooby.org/doc/camel) # camel @@ -26,7 +26,7 @@ depend on [camel-guice](http://camel.apache.org/guice.html), but it provides sim org.jooby jooby-camel - 1.5.0 + 1.6.6 ``` diff --git a/modules/jooby-camel/pom.xml b/modules/jooby-camel/pom.xml index daef257c00..a37a84b29b 100644 --- a/modules/jooby-camel/pom.xml +++ b/modules/jooby-camel/pom.xml @@ -5,7 +5,7 @@ org.jooby modules - 1.5.1-SNAPSHOT + 1.6.9 4.0.0 diff --git a/modules/jooby-cassandra/README.md b/modules/jooby-cassandra/README.md index a6ef4bd2dc..ee8196af46 100644 --- a/modules/jooby-cassandra/README.md +++ b/modules/jooby-cassandra/README.md @@ -1,5 +1,5 @@ -[![Maven Central](https://maven-badges.herokuapp.com/maven-central/org.jooby/jooby-cassandra/badge.svg)](https://maven-badges.herokuapp.com/maven-central/org.jooby/jooby-cassandra) -[![javadoc](https://javadoc.io/badge/org.jooby/jooby-cassandra.svg)](https://javadoc.io/doc/org.jooby/jooby-cassandra/1.5.0) +[![Maven](https://img.shields.io/maven-metadata/v/http/central.maven.org/maven2/org/jooby/jooby-cassandra/maven-metadata.xml.svg)](http://mvnrepository.com/artifact/org.jooby/jooby-cassandra/1.6.6) +[![javadoc](https://javadoc.io/badge/org.jooby/jooby-cassandra.svg)](https://javadoc.io/doc/org.jooby/jooby-cassandra/1.6.6) [![jooby-cassandra website](https://img.shields.io/badge/jooby-cassandra-brightgreen.svg)](http://jooby.org/doc/cassandra) # cassandra @@ -13,7 +13,7 @@ This module offers cassandra database org.jooby jooby-cassandra - 1.5.0 + 1.6.6 ``` @@ -211,7 +211,7 @@ A [Session.Store](/apidocs/org/jooby/cassandra/CassandraSessionStore.html) power org.jooby jooby-cassandra - 1.5.0 + 1.6.6 ``` diff --git a/modules/jooby-cassandra/pom.xml b/modules/jooby-cassandra/pom.xml index e060e7d0c5..25fb0252b3 100644 --- a/modules/jooby-cassandra/pom.xml +++ b/modules/jooby-cassandra/pom.xml @@ -5,7 +5,7 @@ org.jooby modules - 1.5.1-SNAPSHOT + 1.6.9 4.0.0 diff --git a/modules/jooby-commons-email/README.md b/modules/jooby-commons-email/README.md index 1056790be9..813a95dbdd 100644 --- a/modules/jooby-commons-email/README.md +++ b/modules/jooby-commons-email/README.md @@ -1,5 +1,5 @@ -[![Maven Central](https://maven-badges.herokuapp.com/maven-central/org.jooby/jooby-commons-email/badge.svg)](https://maven-badges.herokuapp.com/maven-central/org.jooby/jooby-commons-email) -[![javadoc](https://javadoc.io/badge/org.jooby/jooby-commons-email.svg)](https://javadoc.io/doc/org.jooby/jooby-commons-email/1.5.0) +[![Maven](https://img.shields.io/maven-metadata/v/http/central.maven.org/maven2/org/jooby/jooby-commons-email/maven-metadata.xml.svg)](http://mvnrepository.com/artifact/org.jooby/jooby-commons-email/1.6.6) +[![javadoc](https://javadoc.io/badge/org.jooby/jooby-commons-email.svg)](https://javadoc.io/doc/org.jooby/jooby-commons-email/1.6.6) [![jooby-commons-email website](https://img.shields.io/badge/jooby-commons-email-brightgreen.svg)](http://jooby.org/doc/commons-email) # commons-email @@ -19,7 +19,7 @@ Small but helpful module that provides access to ```Email``` instances. org.jooby jooby-commons-email - 1.5.0 + 1.6.6 ``` diff --git a/modules/jooby-commons-email/pom.xml b/modules/jooby-commons-email/pom.xml index f8cf9268b7..74ead5c107 100644 --- a/modules/jooby-commons-email/pom.xml +++ b/modules/jooby-commons-email/pom.xml @@ -5,7 +5,7 @@ org.jooby modules - 1.5.1-SNAPSHOT + 1.6.9 4.0.0 diff --git a/modules/jooby-consul/README.md b/modules/jooby-consul/README.md index 4b082ce356..faf42ce768 100644 --- a/modules/jooby-consul/README.md +++ b/modules/jooby-consul/README.md @@ -1,5 +1,5 @@ -[![Maven Central](https://maven-badges.herokuapp.com/maven-central/org.jooby/jooby-consul/badge.svg)](https://maven-badges.herokuapp.com/maven-central/org.jooby/jooby-consul) -[![javadoc](https://javadoc.io/badge/org.jooby/jooby-consul.svg)](https://javadoc.io/doc/org.jooby/jooby-consul/1.5.0) +[![Maven](https://img.shields.io/maven-metadata/v/http/central.maven.org/maven2/org/jooby/jooby-consul/maven-metadata.xml.svg)](http://mvnrepository.com/artifact/org.jooby/jooby-consul/1.6.6) +[![javadoc](https://javadoc.io/badge/org.jooby/jooby-consul.svg)](https://javadoc.io/doc/org.jooby/jooby-consul/1.6.6) [![jooby-consul website](https://img.shields.io/badge/jooby-consul-brightgreen.svg)](http://jooby.org/doc/consul) # consul @@ -15,7 +15,7 @@ Also register the application as a service and setup a health check. org.jooby jooby-consul - 1.5.0 + 1.6.6 ``` diff --git a/modules/jooby-consul/pom.xml b/modules/jooby-consul/pom.xml index 218056b3ae..1e72ac3f33 100644 --- a/modules/jooby-consul/pom.xml +++ b/modules/jooby-consul/pom.xml @@ -5,7 +5,7 @@ org.jooby modules - 1.5.1-SNAPSHOT + 1.6.9 4.0.0 diff --git a/modules/jooby-couchbase/README.md b/modules/jooby-couchbase/README.md index 5a01e1eafe..0847d412e3 100644 --- a/modules/jooby-couchbase/README.md +++ b/modules/jooby-couchbase/README.md @@ -1,5 +1,5 @@ -[![Maven Central](https://maven-badges.herokuapp.com/maven-central/org.jooby/jooby-couchbase/badge.svg)](https://maven-badges.herokuapp.com/maven-central/org.jooby/jooby-couchbase) -[![javadoc](https://javadoc.io/badge/org.jooby/jooby-couchbase.svg)](https://javadoc.io/doc/org.jooby/jooby-couchbase/1.5.0) +[![Maven](https://img.shields.io/maven-metadata/v/http/central.maven.org/maven2/org/jooby/jooby-couchbase/maven-metadata.xml.svg)](http://mvnrepository.com/artifact/org.jooby/jooby-couchbase/1.6.6) +[![javadoc](https://javadoc.io/badge/org.jooby/jooby-couchbase.svg)](https://javadoc.io/doc/org.jooby/jooby-couchbase/1.6.6) [![jooby-couchbase website](https://img.shields.io/badge/jooby-couchbase-brightgreen.svg)](http://jooby.org/doc/couchbase) # couchbase @@ -13,7 +13,7 @@ This module provides couchbase access via org.jooby jooby-couchbase - 1.5.0 + 1.6.6 ``` @@ -307,7 +307,7 @@ A [Session.Store](/apidocs/org/jooby/couchbase/CouchbaseSessionStore) powered by org.jooby jooby-couchbase - 1.5.0 + 1.6.6 ``` diff --git a/modules/jooby-couchbase/pom.xml b/modules/jooby-couchbase/pom.xml index 5234639a2f..876ddaca3a 100644 --- a/modules/jooby-couchbase/pom.xml +++ b/modules/jooby-couchbase/pom.xml @@ -5,7 +5,7 @@ org.jooby modules - 1.5.1-SNAPSHOT + 1.6.9 4.0.0 diff --git a/modules/jooby-crash/README.md b/modules/jooby-crash/README.md index b05214043a..bd15da4fd4 100644 --- a/modules/jooby-crash/README.md +++ b/modules/jooby-crash/README.md @@ -1,5 +1,5 @@ -[![Maven Central](https://maven-badges.herokuapp.com/maven-central/org.jooby/jooby-crash/badge.svg)](https://maven-badges.herokuapp.com/maven-central/org.jooby/jooby-crash) -[![javadoc](https://javadoc.io/badge/org.jooby/jooby-crash.svg)](https://javadoc.io/doc/org.jooby/jooby-crash/1.5.0) +[![Maven](https://img.shields.io/maven-metadata/v/http/central.maven.org/maven2/org/jooby/jooby-crash/maven-metadata.xml.svg)](http://mvnrepository.com/artifact/org.jooby/jooby-crash/1.6.6) +[![javadoc](https://javadoc.io/badge/org.jooby/jooby-crash.svg)](https://javadoc.io/doc/org.jooby/jooby-crash/1.6.6) [![jooby-crash website](https://img.shields.io/badge/jooby-crash-brightgreen.svg)](http://jooby.org/doc/crash) # crash @@ -11,7 +11,7 @@ org.jooby jooby-crash - 1.5.0 + 1.6.6 ``` diff --git a/modules/jooby-crash/pom.xml b/modules/jooby-crash/pom.xml index 125bcb1890..6b435dfd4d 100644 --- a/modules/jooby-crash/pom.xml +++ b/modules/jooby-crash/pom.xml @@ -5,7 +5,7 @@ org.jooby modules - 1.5.1-SNAPSHOT + 1.6.9 4.0.0 @@ -87,6 +87,11 @@ crash.shell + + org.crashub + crash.cli + + org.jooby diff --git a/modules/jooby-csl/README.md b/modules/jooby-csl/README.md index 0cd4858c73..dd348ac487 100644 --- a/modules/jooby-csl/README.md +++ b/modules/jooby-csl/README.md @@ -1,5 +1,5 @@ -[![Maven Central](https://maven-badges.herokuapp.com/maven-central/org.jooby/jooby-csl/badge.svg)](https://maven-badges.herokuapp.com/maven-central/org.jooby/jooby-csl) -[![javadoc](https://javadoc.io/badge/org.jooby/jooby-csl.svg)](https://javadoc.io/doc/org.jooby/jooby-csl/1.5.0) +[![Maven](https://img.shields.io/maven-metadata/v/http/central.maven.org/maven2/org/jooby/jooby-csl/maven-metadata.xml.svg)](http://mvnrepository.com/artifact/org.jooby/jooby-csl/1.6.6) +[![javadoc](https://javadoc.io/badge/org.jooby/jooby-csl.svg)](https://javadoc.io/doc/org.jooby/jooby-csl/1.6.6) [![jooby-csl website](https://img.shields.io/badge/jooby-csl-brightgreen.svg)](http://jooby.org/doc/csl) # csl @@ -11,7 +11,7 @@ org.jooby jooby-csl - 1.5.0 + 1.6.6 ``` diff --git a/modules/jooby-csl/pom.xml b/modules/jooby-csl/pom.xml index 2102ecc639..38c6724501 100644 --- a/modules/jooby-csl/pom.xml +++ b/modules/jooby-csl/pom.xml @@ -5,7 +5,7 @@ org.jooby modules - 1.5.1-SNAPSHOT + 1.6.9 4.0.0 diff --git a/modules/jooby-dist/pom.xml b/modules/jooby-dist/pom.xml index 9ddc320876..c4cb02d5bb 100644 --- a/modules/jooby-dist/pom.xml +++ b/modules/jooby-dist/pom.xml @@ -5,7 +5,7 @@ org.jooby modules - 1.5.1-SNAPSHOT + 1.6.9 4.0.0 diff --git a/modules/jooby-dist/src/main/resources/assemblies/jooby.stork.xml b/modules/jooby-dist/src/main/resources/assemblies/jooby.stork.xml index 7d27cc74a7..d9a2275280 100644 --- a/modules/jooby-dist/src/main/resources/assemblies/jooby.stork.xml +++ b/modules/jooby-dist/src/main/resources/assemblies/jooby.stork.xml @@ -18,6 +18,18 @@ 544 **/* + + + **/*.exe + + + + ${project.basedir}${file.separator}src${file.separator}etc${file.separator}bin + true + bin + 544 + + **/*.exe @@ -47,6 +59,16 @@ true **/* + + + **/*.exe + + + + ${project.build.directory}${file.separator}stork${file.separator}bin + bin + + **/*.exe diff --git a/modules/jooby-ebean/README.md b/modules/jooby-ebean/README.md index 01a11f702b..95b985a0df 100644 --- a/modules/jooby-ebean/README.md +++ b/modules/jooby-ebean/README.md @@ -1,5 +1,5 @@ -[![Maven Central](https://maven-badges.herokuapp.com/maven-central/org.jooby/jooby-ebean/badge.svg)](https://maven-badges.herokuapp.com/maven-central/org.jooby/jooby-ebean) -[![javadoc](https://javadoc.io/badge/org.jooby/jooby-ebean.svg)](https://javadoc.io/doc/org.jooby/jooby-ebean/1.5.0) +[![Maven](https://img.shields.io/maven-metadata/v/http/central.maven.org/maven2/org/jooby/jooby-ebean/maven-metadata.xml.svg)](http://mvnrepository.com/artifact/org.jooby/jooby-ebean/1.6.6) +[![javadoc](https://javadoc.io/badge/org.jooby/jooby-ebean.svg)](https://javadoc.io/doc/org.jooby/jooby-ebean/1.6.6) [![jooby-ebean website](https://img.shields.io/badge/jooby-ebean-brightgreen.svg)](http://jooby.org/doc/ebean) # ebean @@ -17,7 +17,7 @@ Object-Relational-Mapping via [Ebean ORM](http://ebean-orm.github.io). It config org.jooby jooby-ebean - 1.5.0 + 1.6.6 ``` diff --git a/modules/jooby-ebean/pom.xml b/modules/jooby-ebean/pom.xml index f5a0d3ef5d..74988b22ad 100644 --- a/modules/jooby-ebean/pom.xml +++ b/modules/jooby-ebean/pom.xml @@ -5,7 +5,7 @@ org.jooby modules - 1.5.1-SNAPSHOT + 1.6.9 4.0.0 diff --git a/modules/jooby-ehcache/README.md b/modules/jooby-ehcache/README.md index 706e0a3ce4..72d52aee40 100644 --- a/modules/jooby-ehcache/README.md +++ b/modules/jooby-ehcache/README.md @@ -1,5 +1,5 @@ -[![Maven Central](https://maven-badges.herokuapp.com/maven-central/org.jooby/jooby-ehcache/badge.svg)](https://maven-badges.herokuapp.com/maven-central/org.jooby/jooby-ehcache) -[![javadoc](https://javadoc.io/badge/org.jooby/jooby-ehcache.svg)](https://javadoc.io/doc/org.jooby/jooby-ehcache/1.5.0) +[![Maven](https://img.shields.io/maven-metadata/v/http/central.maven.org/maven2/org/jooby/jooby-ehcache/maven-metadata.xml.svg)](http://mvnrepository.com/artifact/org.jooby/jooby-ehcache/1.6.6) +[![javadoc](https://javadoc.io/badge/org.jooby/jooby-ehcache.svg)](https://javadoc.io/doc/org.jooby/jooby-ehcache/1.6.6) [![jooby-ehcache website](https://img.shields.io/badge/jooby-ehcache-brightgreen.svg)](http://jooby.org/doc/ehcache) # ehcache @@ -16,7 +16,7 @@ Provides advanced cache features via [Ehcache](http://ehcache.org) org.jooby jooby-ehcache - 1.5.0 + 1.6.6 ``` @@ -120,7 +120,7 @@ Please note the ```default``` cache works as a template and isn't a real/usable org.jooby jooby-ehcache - 1.5.0 + 1.6.6 ``` diff --git a/modules/jooby-ehcache/pom.xml b/modules/jooby-ehcache/pom.xml index 64549299e9..386e722186 100644 --- a/modules/jooby-ehcache/pom.xml +++ b/modules/jooby-ehcache/pom.xml @@ -5,7 +5,7 @@ org.jooby modules - 1.5.1-SNAPSHOT + 1.6.9 4.0.0 diff --git a/modules/jooby-elasticsearch/README.md b/modules/jooby-elasticsearch/README.md index 356facdefb..1c8113643a 100644 --- a/modules/jooby-elasticsearch/README.md +++ b/modules/jooby-elasticsearch/README.md @@ -1,5 +1,5 @@ -[![Maven Central](https://maven-badges.herokuapp.com/maven-central/org.jooby/jooby-elasticsearch/badge.svg)](https://maven-badges.herokuapp.com/maven-central/org.jooby/jooby-elasticsearch) -[![javadoc](https://javadoc.io/badge/org.jooby/jooby-elasticsearch.svg)](https://javadoc.io/doc/org.jooby/jooby-elasticsearch/1.5.0) +[![Maven](https://img.shields.io/maven-metadata/v/http/central.maven.org/maven2/org/jooby/jooby-elasticsearch/maven-metadata.xml.svg)](http://mvnrepository.com/artifact/org.jooby/jooby-elasticsearch/1.6.6) +[![javadoc](https://javadoc.io/badge/org.jooby/jooby-elasticsearch.svg)](https://javadoc.io/doc/org.jooby/jooby-elasticsearch/1.6.6) [![jooby-elasticsearch website](https://img.shields.io/badge/jooby-elasticsearch-brightgreen.svg)](http://jooby.org/doc/elasticsearch) # elasticsearch @@ -15,7 +15,7 @@ Open Source, Distributed, RESTful Search Engine via [Elastic Search](https://git org.jooby jooby-elasticsearch - 1.5.0 + 1.6.6 ``` diff --git a/modules/jooby-elasticsearch/pom.xml b/modules/jooby-elasticsearch/pom.xml index 8d9a676906..e7306fedd7 100644 --- a/modules/jooby-elasticsearch/pom.xml +++ b/modules/jooby-elasticsearch/pom.xml @@ -5,7 +5,7 @@ org.jooby modules - 1.5.1-SNAPSHOT + 1.6.9 4.0.0 @@ -42,7 +42,7 @@ org.elasticsearch.client - rest + elasticsearch-rest-high-level-client diff --git a/modules/jooby-elasticsearch/src/main/java/org/jooby/elasticsearch/Elasticsearch.java b/modules/jooby-elasticsearch/src/main/java/org/jooby/elasticsearch/Elasticsearch.java index 02d189e8e5..52efddc9c9 100644 --- a/modules/jooby-elasticsearch/src/main/java/org/jooby/elasticsearch/Elasticsearch.java +++ b/modules/jooby-elasticsearch/src/main/java/org/jooby/elasticsearch/Elasticsearch.java @@ -207,6 +207,7 @@ import org.apache.http.HttpHost; import org.elasticsearch.client.RestClient; +import org.elasticsearch.client.RestHighLevelClient; import org.jooby.Env; import org.jooby.Jooby; @@ -219,7 +220,7 @@ * Full text search and analytics via Elastic * Search. *

- * Provides a RESTFul client. + * Provides a high and low level Elasticsearch REST client. * *

usage

* @@ -231,17 +232,20 @@ *

client API

*

- * The module exposes a {@link RestClient} instance + * The module exposes a {@link RestHighLevelClient} and a low-level {@link RestClient} instance *

* *
{@code
  *
  * put("/:id", req -> {
  *   // index a document
- *   RestClient client = req.require(RestClient.class);
- *   StringEntity data = new StringEntity("{\"foo\":\"bar\"}");
- *   return client.performRequest("PUT", "/twitter/tweet/" + req.param("id").value(), Collections.emptyMap(), data)
- *     .getEntity().getContent();
+ *   IndexRequest indexRequest = new IndexRequest("posts")
+ *     .id("1")
+ *     .source("user", "kimchy",
+ *         "postDate", new Date(),
+ *         "message", "trying out Elasticsearch");
+ *   RestHighLevelClient client = req.require(RestHighLevelClient .class);
+ *   return client.index(request, RequestOptions.DEFAULT).toString();
  * });
  *
  * }
@@ -264,10 +268,13 @@ public Elasticsearch(final String ... hosts) { @Override public void configure(final Env env, final Config config, final Binder binder) { HttpHost[] httpHosts = Arrays.stream(hosts).map(HttpHost::create).toArray(HttpHost[]::new); - RestClient restClient = RestClient.builder(httpHosts).build(); + RestHighLevelClient restHighLevelClient = new RestHighLevelClient(RestClient.builder(httpHosts)); + RestClient restClient = restHighLevelClient.getLowLevelClient(); + binder.bind(RestClient.class).toInstance(restClient); + binder.bind(RestHighLevelClient.class).toInstance(restHighLevelClient); - env.onStop(restClient::close); + env.onStop(restHighLevelClient::close); } @Override diff --git a/modules/jooby-elasticsearch/src/test/java/org/jooby/elasticsearch/ElasticsearchTest.java b/modules/jooby-elasticsearch/src/test/java/org/jooby/elasticsearch/ElasticsearchTest.java index 603d967240..2cfc3fd643 100644 --- a/modules/jooby-elasticsearch/src/test/java/org/jooby/elasticsearch/ElasticsearchTest.java +++ b/modules/jooby-elasticsearch/src/test/java/org/jooby/elasticsearch/ElasticsearchTest.java @@ -7,6 +7,7 @@ import com.typesafe.config.ConfigFactory; import static org.easymock.EasyMock.expect; import org.elasticsearch.client.RestClient; +import org.elasticsearch.client.RestHighLevelClient; import org.jooby.Env; import org.jooby.test.MockUnit; import org.jooby.funzy.Throwing; @@ -32,16 +33,21 @@ public class ElasticsearchTest { private MockUnit.Block nb = unit -> { RestClient client = unit.mock(RestClient.class); unit.registerMock(RestClient.class, client); + RestHighLevelClient restHighLevelClient = unit.mock(RestHighLevelClient.class); + unit.registerMock(RestHighLevelClient.class, restHighLevelClient); }; @SuppressWarnings("unchecked") private MockUnit.Block bindings = unit -> { AnnotatedBindingBuilder abbclient = unit.mock(AnnotatedBindingBuilder.class); abbclient.toInstance(unit.capture(RestClient.class)); - //abbclient.toInstance(anyObject(RestClient.class)); + + AnnotatedBindingBuilder defclient = unit.mock(AnnotatedBindingBuilder.class); + defclient.toInstance(unit.capture(RestHighLevelClient.class)); Binder binder = unit.get(Binder.class); expect(binder.bind(RestClient.class)).andReturn(abbclient); + expect(binder.bind(RestHighLevelClient.class)).andReturn(defclient); }; @Test @@ -57,6 +63,9 @@ public void defaults() throws Exception { List captured = unit.captured(RestClient.class); assert captured.size() == 1; + List capturedHighLevelRestClient = unit.captured(RestHighLevelClient.class); + assert capturedHighLevelRestClient.size() == 1; + List callbacks = unit.captured(Throwing.Runnable.class); callbacks.get(0).run(); }); diff --git a/modules/jooby-eventbus/README.md b/modules/jooby-eventbus/README.md index 7e74f18a4b..0e22f37f66 100644 --- a/modules/jooby-eventbus/README.md +++ b/modules/jooby-eventbus/README.md @@ -1,5 +1,5 @@ -[![Maven Central](https://maven-badges.herokuapp.com/maven-central/org.jooby/jooby-eventbus/badge.svg)](https://maven-badges.herokuapp.com/maven-central/org.jooby/jooby-eventbus) -[![javadoc](https://javadoc.io/badge/org.jooby/jooby-eventbus.svg)](https://javadoc.io/doc/org.jooby/jooby-eventbus/1.5.0) +[![Maven](https://img.shields.io/maven-metadata/v/http/central.maven.org/maven2/org/jooby/jooby-eventbus/maven-metadata.xml.svg)](http://mvnrepository.com/artifact/org.jooby/jooby-eventbus/1.6.6) +[![javadoc](https://javadoc.io/badge/org.jooby/jooby-eventbus.svg)](https://javadoc.io/doc/org.jooby/jooby-eventbus/1.6.6) [![jooby-eventbus website](https://img.shields.io/badge/jooby-eventbus-brightgreen.svg)](http://jooby.org/doc/eventbus) # EventBus @@ -15,7 +15,7 @@ org.jooby jooby-eventbus - 1.5.0 + 1.6.6 ``` diff --git a/modules/jooby-eventbus/pom.xml b/modules/jooby-eventbus/pom.xml index e07ab5d33f..125f00e792 100644 --- a/modules/jooby-eventbus/pom.xml +++ b/modules/jooby-eventbus/pom.xml @@ -5,7 +5,7 @@ org.jooby modules - 1.5.1-SNAPSHOT + 1.6.9 4.0.0 diff --git a/modules/jooby-executor/README.md b/modules/jooby-executor/README.md index a4fff6ece3..6fca36007d 100644 --- a/modules/jooby-executor/README.md +++ b/modules/jooby-executor/README.md @@ -1,5 +1,5 @@ -[![Maven Central](https://maven-badges.herokuapp.com/maven-central/org.jooby/jooby-executor/badge.svg)](https://maven-badges.herokuapp.com/maven-central/org.jooby/jooby-executor) -[![javadoc](https://javadoc.io/badge/org.jooby/jooby-executor.svg)](https://javadoc.io/doc/org.jooby/jooby-executor/1.5.0) +[![Maven](https://img.shields.io/maven-metadata/v/http/central.maven.org/maven2/org/jooby/jooby-executor/maven-metadata.xml.svg)](http://mvnrepository.com/artifact/org.jooby/jooby-executor/1.6.6) +[![javadoc](https://javadoc.io/badge/org.jooby/jooby-executor.svg)](https://javadoc.io/doc/org.jooby/jooby-executor/1.6.6) [![jooby-executor website](https://img.shields.io/badge/jooby-executor-brightgreen.svg)](http://jooby.org/doc/executor) # executor @@ -15,7 +15,7 @@ Manage the life cycle of {@link ExecutorService} and build async apps, schedule org.jooby jooby-executor - 1.5.0 + 1.6.6 ``` diff --git a/modules/jooby-executor/pom.xml b/modules/jooby-executor/pom.xml index cadd9dc9b0..7d9e9a8d97 100644 --- a/modules/jooby-executor/pom.xml +++ b/modules/jooby-executor/pom.xml @@ -5,7 +5,7 @@ org.jooby modules - 1.5.1-SNAPSHOT + 1.6.9 4.0.0 diff --git a/modules/jooby-exposed/README.md b/modules/jooby-exposed/README.md new file mode 100644 index 0000000000..baaaf2ae79 --- /dev/null +++ b/modules/jooby-exposed/README.md @@ -0,0 +1,52 @@ +[![Maven](https://img.shields.io/maven-metadata/v/http/central.maven.org/maven2/org/jooby/jooby-exposed/maven-metadata.xml.svg)](http://mvnrepository.com/artifact/org.jooby/jooby-exposed/1.6.6) +[![javadoc](https://javadoc.io/badge/org.jooby/jooby-exposed.svg)](https://javadoc.io/doc/org.jooby/jooby-exposed/1.6.6) +[![jooby-exposed website](https://img.shields.io/badge/jooby-exposed-brightgreen.svg)](http://jooby.org/doc/exposed) +# exposed + + Exposed is a prototype for a lightweight SQL library written over JDBC driver for Kotlin language + +> NOTE: This module depends on [jdbc](https://github.com/jooby-project/jooby/tree/master/jooby-jdbc) module. + +## exports + +* Database object + +## usage + +```java +{ + use(Jdbc()) + use(Exposed()) + + get("/db") { + val db = require(Database::class) + transaction (db) { + // Work with db... + } + } + } +``` + +## multiple databases + +```java +{ + use(Jdbc("db1")) + + use(Jdbc("db2")) + + use(Exposed("db1")) + + use(Exposed("db2")) + + get("/db") { + val db1 = require("db1", Database::class) + // Work with db1... + + val db2 = require("db2", Database::class) + // Work with db2... + } +} +``` + +That's all! Happy coding!!! diff --git a/modules/jooby-exposed/pom.xml b/modules/jooby-exposed/pom.xml new file mode 100644 index 0000000000..2eb69a793b --- /dev/null +++ b/modules/jooby-exposed/pom.xml @@ -0,0 +1,221 @@ + + + + + org.jooby + modules + 1.6.9 + + + 4.0.0 + jooby-exposed + + + + + kotlin-maven-plugin + org.jetbrains.kotlin + ${kotlin.version} + + 1.8 + + -java-parameters + + + + + compile + compile + + compile + + + + test-compile + test-compile + + test-compile + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + + + + default-compile + none + + + + default-testCompile + none + + + java-compile + compile + + compile + + + + java-test-compile + test-compile + + testCompile + + + + + + + org.apache.maven.plugins + maven-source-plugin + + + verify + + jar + + + + **/*.java + **/*.kt + + + + + + + + org.jetbrains.dokka + dokka-maven-plugin + ${dokka-maven-plugin.version} + + + verify + + javadocJar + + + + + + + + org.apache.maven.plugins + maven-surefire-plugin + + + **/*Test.java + **/*Feature.java + **/Issue*.java + + + + + + + + + + org.jooby + jooby-jdbc + ${project.version} + + + + + org.jooby + jooby + ${project.version} + + + + + org.jetbrains.exposed + exposed + ${exposed.version} + + + + + org.jooby + jooby + ${project.version} + test + tests + + + + org.jooby + jooby-netty + ${project.version} + test + + + + junit + junit + test + + + + org.easymock + easymock + test + + + + org.powermock + powermock-api-easymock + test + + + + org.powermock + powermock-module-junit4 + test + + + + org.jacoco + org.jacoco.agent + runtime + test + + + org.jetbrains.kotlin + kotlin-stdlib-jdk8 + ${kotlin.version} + + + org.jetbrains.kotlin + kotlin-test + ${kotlin.version} + test + + + + + + exposed + exposed + https://dl.bintray.com/kotlin/exposed + + + + + + jcenter + JCenter + https://jcenter.bintray.com/ + + + + diff --git a/modules/jooby-exposed/src/main/java/org/jooby/exposed/Exposed.kt b/modules/jooby-exposed/src/main/java/org/jooby/exposed/Exposed.kt new file mode 100644 index 0000000000..813e90e12c --- /dev/null +++ b/modules/jooby-exposed/src/main/java/org/jooby/exposed/Exposed.kt @@ -0,0 +1,78 @@ +package org.jooby.exposed + +import com.google.inject.Binder +import com.google.inject.Key +import com.google.inject.name.Names +import com.typesafe.config.Config +import org.jetbrains.exposed.sql.Database +import org.jooby.Env +import org.jooby.Jooby +import java.util.NoSuchElementException +import javax.sql.DataSource + +/** + *

exposed

+ *

+ * Exposed is a prototype for a lightweight SQL + * library written over JDBC driver for Kotlin language + *

+ * + *

+ * This module depends on {@link org.jooby.jdbc.Jdbc} module, make sure you read the doc of the + * {@link org.jooby.jdbc.Jdbc} module. + *

+ * + *

exports

+ *
    + *
  • One or more Database objects
  • + *
+ * + *

usage

+ *
{@code
+ * {
+ *   use(new Jdbc());
+ *
+ *   use(new Exposed());
+ *
+ *   get("/db") {
+ *     val db = require(Database::class)
+ *     transaction (db) {
+ *       // Work with db...
+ *     }
+ *   }
+ * }
+ * }
+ * + *

multiple databases

+ * + *
{@code
+ * {
+ *   use(new Jdbc("db1"));
+ *
+ *   use(new Jdbc("db2"));
+ *
+ *   use(new Exposed("db1"));
+ *
+ *   use(new Exposed("db2"));
+ *
+ *   get("/db") {
+ *     val db1 = require("db1", Database::class)
+ *     // Work with db1...
+ *
+ *     val db2 = require("db2", Database::class)
+ *     // Work with db2...
+ *   }
+ * }
+ * }
+ * + * @author edgar + */ +class Exposed(val name: String = "db") : Jooby.Module { + override fun configure(env: Env, conf: Config, binder: Binder) { + val dskey = Key.get(DataSource::class.java, Names.named(name)) + val ds = env.get(dskey) + .orElseThrow { NoSuchElementException("DataSource missing: $dskey") } + val db = Database.connect(ds) + env.serviceKey().generate(Database::class.java, name) { key -> binder.bind(key).toInstance(db) } + } +} diff --git a/modules/jooby-exposed/src/test/java/org/jooby/exposed/ExposedTest.kt b/modules/jooby-exposed/src/test/java/org/jooby/exposed/ExposedTest.kt new file mode 100644 index 0000000000..e4bd66a2e2 --- /dev/null +++ b/modules/jooby-exposed/src/test/java/org/jooby/exposed/ExposedTest.kt @@ -0,0 +1,78 @@ +package org.jooby.exposed + +import com.google.inject.Binder +import com.google.inject.Key +import com.google.inject.binder.LinkedBindingBuilder +import com.google.inject.name.Names +import com.typesafe.config.Config +import org.easymock.EasyMock +import org.jetbrains.exposed.sql.Database +import org.jooby.Env +import org.jooby.test.MockUnit +import org.junit.Test +import java.util.* +import java.util.function.Consumer +import javax.sql.DataSource + +class ExposedTest { + + @Test + fun defaults() { + val dbkey = Key.get(Database::class.java, Names.named("db")) + val blocks = arrayOf(MockUnit.Block { unit -> + Exposed().configure(unit.get(Env::class.java), unit.get(Config::class.java), unit.get(Binder::class.java)) + }, MockUnit.Block { unit -> + val binder = unit.captured(Consumer::class.java)[0] as Consumer> + binder.accept(dbkey) + }) + + MockUnit(Env::class.java, Binder::class.java, Config::class.java, DataSource::class.java) + .expect(dataSource("db")) + .expect(serviceKey("db")) + .expect(bind(dbkey)) + .run(*blocks) + } + + @Test(expected = NoSuchElementException::class) + fun noDataSource() { + val blocks = arrayOf(MockUnit.Block { unit -> + Exposed().configure(unit.get(Env::class.java), unit.get(Config::class.java), unit.get(Binder::class.java)) + }) + + MockUnit(Env::class.java, Binder::class.java, Config::class.java, DataSource::class.java) + .expect { unit -> + val env = unit.get(Env::class.java) + EasyMock.expect(env.get(Key.get(DataSource::class.java, Names.named("db")))).andReturn(Optional.empty()) + } + .run(*blocks) + } + + private fun bind(key: Key): MockUnit.Block { + return MockUnit.Block { unit -> + val lbb = unit.mock(LinkedBindingBuilder::class.java) as LinkedBindingBuilder + lbb.toInstance(EasyMock.isA(Database::class.java)) + + val binder = unit.get(Binder::class.java) + EasyMock.expect(binder.bind(key)).andReturn(lbb) + } + } + + private fun serviceKey(name: String): MockUnit.Block { + return MockUnit.Block { unit -> + val skey = unit.mock(Env.ServiceKey::class.java) + skey.generate(EasyMock.eq(Database::class.java), EasyMock.eq(name), unit.capture(Consumer::class.java) as Consumer>?); + + val env = unit.get(Env::class.java) + EasyMock.expect(env.serviceKey()).andReturn(skey) + } + } + + private fun dataSource(db: String?): MockUnit.Block { + return MockUnit.Block { unit -> + val ds = unit.get(DataSource::class.java) + val env = unit.get(Env::class.java) + val ods = if (db == null) Optional.empty() else Optional.of(ds) + EasyMock.expect(env.get(Key.get(DataSource::class.java, Names.named(db)))).andReturn(ods) + } + } +} diff --git a/modules/jooby-filewatcher/README.md b/modules/jooby-filewatcher/README.md index 4681c2291b..4c8c4d9915 100644 --- a/modules/jooby-filewatcher/README.md +++ b/modules/jooby-filewatcher/README.md @@ -1,5 +1,5 @@ -[![Maven Central](https://maven-badges.herokuapp.com/maven-central/org.jooby/jooby-filewatcher/badge.svg)](https://maven-badges.herokuapp.com/maven-central/org.jooby/jooby-filewatcher) -[![javadoc](https://javadoc.io/badge/org.jooby/jooby-filewatcher.svg)](https://javadoc.io/doc/org.jooby/jooby-filewatcher/1.5.0) +[![Maven](https://img.shields.io/maven-metadata/v/http/central.maven.org/maven2/org/jooby/jooby-filewatcher/maven-metadata.xml.svg)](http://mvnrepository.com/artifact/org.jooby/jooby-filewatcher/1.6.6) +[![javadoc](https://javadoc.io/badge/org.jooby/jooby-filewatcher.svg)](https://javadoc.io/doc/org.jooby/jooby-filewatcher/1.6.6) [![jooby-filewatcher website](https://img.shields.io/badge/jooby-filewatcher-brightgreen.svg)](http://jooby.org/doc/filewatcher) # file watcher @@ -11,7 +11,7 @@ Watches for file system changes or event. It uses a watch service to monitor a d org.jooby jooby-file watcher - 1.5.0 + 1.6.6 ``` diff --git a/modules/jooby-filewatcher/pom.xml b/modules/jooby-filewatcher/pom.xml index 23731d1324..1824d76b75 100644 --- a/modules/jooby-filewatcher/pom.xml +++ b/modules/jooby-filewatcher/pom.xml @@ -5,7 +5,7 @@ org.jooby modules - 1.5.1-SNAPSHOT + 1.6.9 4.0.0 diff --git a/modules/jooby-filewatcher/src/main/java/org/jooby/filewatcher/FileEventOptions.java b/modules/jooby-filewatcher/src/main/java/org/jooby/filewatcher/FileEventOptions.java index a0810fd97a..63c3a9929b 100644 --- a/modules/jooby-filewatcher/src/main/java/org/jooby/filewatcher/FileEventOptions.java +++ b/modules/jooby-filewatcher/src/main/java/org/jooby/filewatcher/FileEventOptions.java @@ -203,6 +203,8 @@ */ package org.jooby.filewatcher; +import org.jooby.spi.WatchEventModifier; + import static java.nio.file.StandardWatchEventKinds.ENTRY_CREATE; import static java.nio.file.StandardWatchEventKinds.ENTRY_DELETE; import static java.nio.file.StandardWatchEventKinds.ENTRY_MODIFY; @@ -256,7 +258,7 @@ public String toString() { private final List matchers = new ArrayList<>(); - private Modifier modifier = new WatchEventModifier("HIGH"); + private Modifier modifier = WatchEventModifier.modifier("HIGH"); private boolean recursive = true; diff --git a/modules/jooby-filewatcher/src/main/java/org/jooby/filewatcher/FileWatcher.java b/modules/jooby-filewatcher/src/main/java/org/jooby/filewatcher/FileWatcher.java index 986270c8f2..f0a224ea55 100644 --- a/modules/jooby-filewatcher/src/main/java/org/jooby/filewatcher/FileWatcher.java +++ b/modules/jooby-filewatcher/src/main/java/org/jooby/filewatcher/FileWatcher.java @@ -211,6 +211,7 @@ import org.jooby.Env; import org.jooby.Jooby.Module; import org.jooby.funzy.Throwing; +import org.jooby.spi.WatchEventModifier; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -548,7 +549,7 @@ private void paths(final ClassLoader loader, final Config conf, final String nam Path path = Paths.get(coptions.getString("path")); FileEventOptions options = new FileEventOptions(path, handler); list(coptions, "kind", it -> options.kind(new WatchEventKind(it.toString()))); - list(coptions, "modifier", it -> options.modifier(new WatchEventModifier(it.toString()))); + list(coptions, "modifier", it -> options.modifier(WatchEventModifier.modifier(it.toString()))); list(coptions, "includes", it -> options.includes(it.toString())); list(coptions, "recursive", it -> options.recursive(Boolean.valueOf(it.toString()))); callback.accept(options); diff --git a/modules/jooby-filewatcher/src/test/java/org/jooby/filewatcher/WatchEventModifierTest.java b/modules/jooby-filewatcher/src/test/java/org/jooby/filewatcher/WatchEventModifierTest.java index e89014f894..3f4fbfae49 100644 --- a/modules/jooby-filewatcher/src/test/java/org/jooby/filewatcher/WatchEventModifierTest.java +++ b/modules/jooby-filewatcher/src/test/java/org/jooby/filewatcher/WatchEventModifierTest.java @@ -2,14 +2,16 @@ import static org.junit.Assert.assertEquals; +import org.jooby.spi.WatchEventModifier; import org.junit.Test; +import java.nio.file.WatchEvent; + public class WatchEventModifierTest { @Test public void watchEventModifier() { - WatchEventModifier mod = new WatchEventModifier("foo"); + WatchEvent.Modifier mod = WatchEventModifier.modifier("FOO"); assertEquals("FOO", mod.name()); - assertEquals("FOO", mod.toString()); } } diff --git a/modules/jooby-flyway/README.md b/modules/jooby-flyway/README.md index 95af4ed405..0da3ff6e68 100644 --- a/modules/jooby-flyway/README.md +++ b/modules/jooby-flyway/README.md @@ -1,5 +1,5 @@ -[![Maven Central](https://maven-badges.herokuapp.com/maven-central/org.jooby/jooby-flyway/badge.svg)](https://maven-badges.herokuapp.com/maven-central/org.jooby/jooby-flyway) -[![javadoc](https://javadoc.io/badge/org.jooby/jooby-flyway.svg)](https://javadoc.io/doc/org.jooby/jooby-flyway/1.5.0) +[![Maven](https://img.shields.io/maven-metadata/v/http/central.maven.org/maven2/org/jooby/jooby-flyway/maven-metadata.xml.svg)](http://mvnrepository.com/artifact/org.jooby/jooby-flyway/1.6.6) +[![javadoc](https://javadoc.io/badge/org.jooby/jooby-flyway.svg)](https://javadoc.io/doc/org.jooby/jooby-flyway/1.6.6) [![jooby-flyway website](https://img.shields.io/badge/jooby-flyway-brightgreen.svg)](http://jooby.org/doc/flyway) # flyway @@ -15,7 +15,7 @@ This module run [Flyway](http://flywaydb.org) on startup and apply database migr org.jooby jooby-flyway - 1.5.0 + 1.6.6 ``` diff --git a/modules/jooby-flyway/pom.xml b/modules/jooby-flyway/pom.xml index 4395f82f3c..3c4492dd0c 100644 --- a/modules/jooby-flyway/pom.xml +++ b/modules/jooby-flyway/pom.xml @@ -5,7 +5,7 @@ org.jooby modules - 1.5.1-SNAPSHOT + 1.6.9 4.0.0 diff --git a/modules/jooby-frontend/README.md b/modules/jooby-frontend/README.md index 36421d7822..81eaf246a7 100644 --- a/modules/jooby-frontend/README.md +++ b/modules/jooby-frontend/README.md @@ -1,5 +1,5 @@ -[![Maven Central](https://maven-badges.herokuapp.com/maven-central/org.jooby/jooby-frontend/badge.svg)](https://maven-badges.herokuapp.com/maven-central/org.jooby/jooby-frontend) -[![javadoc](https://javadoc.io/badge/org.jooby/jooby-frontend.svg)](https://javadoc.io/doc/org.jooby/jooby-frontend/1.5.0) +[![Maven](https://img.shields.io/maven-metadata/v/http/central.maven.org/maven2/org/jooby/jooby-frontend/maven-metadata.xml.svg)](http://mvnrepository.com/artifact/org.jooby/jooby-frontend/1.6.6) +[![javadoc](https://javadoc.io/badge/org.jooby/jooby-frontend.svg)](https://javadoc.io/doc/org.jooby/jooby-frontend/1.6.6) [![jooby-frontend website](https://img.shields.io/badge/jooby-frontend-brightgreen.svg)](http://jooby.org/doc/frontend) # frontend @@ -12,7 +12,7 @@ runs npm, w org.jooby jooby-frontend - 1.5.0 + 1.6.6 ``` diff --git a/modules/jooby-frontend/pom.xml b/modules/jooby-frontend/pom.xml index ca6270c4a8..952adea263 100644 --- a/modules/jooby-frontend/pom.xml +++ b/modules/jooby-frontend/pom.xml @@ -5,7 +5,7 @@ org.jooby modules - 1.5.1-SNAPSHOT + 1.6.9 4.0.0 diff --git a/modules/jooby-ftl/README.md b/modules/jooby-ftl/README.md index 4e0cbc0ac4..99bd1dd0cb 100644 --- a/modules/jooby-ftl/README.md +++ b/modules/jooby-ftl/README.md @@ -1,5 +1,5 @@ -[![Maven Central](https://maven-badges.herokuapp.com/maven-central/org.jooby/jooby-ftl/badge.svg)](https://maven-badges.herokuapp.com/maven-central/org.jooby/jooby-ftl) -[![javadoc](https://javadoc.io/badge/org.jooby/jooby-ftl.svg)](https://javadoc.io/doc/org.jooby/jooby-ftl/1.5.0) +[![Maven](https://img.shields.io/maven-metadata/v/http/central.maven.org/maven2/org/jooby/jooby-ftl/maven-metadata.xml.svg)](http://mvnrepository.com/artifact/org.jooby/jooby-ftl/1.6.6) +[![javadoc](https://javadoc.io/badge/org.jooby/jooby-ftl.svg)](https://javadoc.io/doc/org.jooby/jooby-ftl/1.6.6) [![jooby-ftl website](https://img.shields.io/badge/jooby-ftl-brightgreen.svg)](http://jooby.org/doc/ftl) # freemarker @@ -16,7 +16,7 @@ org.jooby jooby-ftl - 1.5.0 + 1.6.6 ``` diff --git a/modules/jooby-ftl/pom.xml b/modules/jooby-ftl/pom.xml index 3dfc4b4bb5..e4a9ff880b 100644 --- a/modules/jooby-ftl/pom.xml +++ b/modules/jooby-ftl/pom.xml @@ -5,7 +5,7 @@ org.jooby modules - 1.5.1-SNAPSHOT + 1.6.9 4.0.0 diff --git a/modules/jooby-gradle-plugin/README.md b/modules/jooby-gradle-plugin/README.md index e142a32336..cd3d512c18 100644 --- a/modules/jooby-gradle-plugin/README.md +++ b/modules/jooby-gradle-plugin/README.md @@ -1,5 +1,5 @@ -[![Maven Central](https://maven-badges.herokuapp.com/maven-central/org.jooby/jooby-gradle-plugin/badge.svg)](https://maven-badges.herokuapp.com/maven-central/org.jooby/jooby-gradle-plugin) -[![javadoc](https://javadoc.io/badge/org.jooby/jooby-gradle-plugin.svg)](https://javadoc.io/doc/org.jooby/jooby-gradle-plugin/1.5.0) +[![Maven](https://img.shields.io/maven-metadata/v/http/central.maven.org/maven2/org/jooby/jooby-gradle-plugin/maven-metadata.xml.svg)](http://mvnrepository.com/artifact/org.jooby/jooby-gradle-plugin/1.6.6) +[![javadoc](https://javadoc.io/badge/org.jooby/jooby-gradle-plugin.svg)](https://javadoc.io/doc/org.jooby/jooby-gradle-plugin/1.6.6) [![jooby-gradle-plugin website](https://img.shields.io/badge/jooby-gradle-plugin-brightgreen.svg)](http://jooby.org/doc/gradle-plugin) # gradle plugin @@ -21,7 +21,7 @@ buildscript { dependencies { /** joobyRun */ - classpath group: 'org.jooby', name: 'jooby-gradle-plugin', version: '1.5.0' + classpath group: 'org.jooby', name: 'jooby-gradle-plugin', version: '1.6.6' } } diff --git a/modules/jooby-gradle-plugin/pom.xml b/modules/jooby-gradle-plugin/pom.xml index 7e9b9f040f..0647059b5f 100644 --- a/modules/jooby-gradle-plugin/pom.xml +++ b/modules/jooby-gradle-plugin/pom.xml @@ -6,7 +6,7 @@ org.jooby modules - 1.5.1-SNAPSHOT + 1.6.9 4.0.0 diff --git a/modules/jooby-gson/README.md b/modules/jooby-gson/README.md index 3ee5202a6f..b7a9facfeb 100644 --- a/modules/jooby-gson/README.md +++ b/modules/jooby-gson/README.md @@ -1,5 +1,5 @@ -[![Maven Central](https://maven-badges.herokuapp.com/maven-central/org.jooby/jooby-gson/badge.svg)](https://maven-badges.herokuapp.com/maven-central/org.jooby/jooby-gson) -[![javadoc](https://javadoc.io/badge/org.jooby/jooby-gson.svg)](https://javadoc.io/doc/org.jooby/jooby-gson/1.5.0) +[![Maven](https://img.shields.io/maven-metadata/v/http/central.maven.org/maven2/org/jooby/jooby-gson/maven-metadata.xml.svg)](http://mvnrepository.com/artifact/org.jooby/jooby-gson/1.6.6) +[![javadoc](https://javadoc.io/badge/org.jooby/jooby-gson.svg)](https://javadoc.io/doc/org.jooby/jooby-gson/1.6.6) [![jooby-gson website](https://img.shields.io/badge/jooby-gson-brightgreen.svg)](http://jooby.org/doc/gson) # gson @@ -17,7 +17,7 @@ JSON support via [Gson](https://github.com/google/gson) library. org.jooby jooby-gson - 1.5.0 + 1.6.6 ``` diff --git a/modules/jooby-gson/pom.xml b/modules/jooby-gson/pom.xml index fc7c5798d1..3391e50156 100644 --- a/modules/jooby-gson/pom.xml +++ b/modules/jooby-gson/pom.xml @@ -5,7 +5,7 @@ org.jooby modules - 1.5.1-SNAPSHOT + 1.6.9 4.0.0 diff --git a/modules/jooby-gson/src/main/java/org/jooby/json/GsonRawRenderer.java b/modules/jooby-gson/src/main/java/org/jooby/json/GsonRawRenderer.java new file mode 100644 index 0000000000..c2d30426c8 --- /dev/null +++ b/modules/jooby-gson/src/main/java/org/jooby/json/GsonRawRenderer.java @@ -0,0 +1,222 @@ +/** + * Apache License + * Version 2.0, January 2004 + * http://www.apache.org/licenses/ + * + * TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + * + * 1. Definitions. + * + * "License" shall mean the terms and conditions for use, reproduction, + * and distribution as defined by Sections 1 through 9 of this document. + * + * "Licensor" shall mean the copyright owner or entity authorized by + * the copyright owner that is granting the License. + * + * "Legal Entity" shall mean the union of the acting entity and all + * other entities that control, are controlled by, or are under common + * control with that entity. For the purposes of this definition, + * "control" means (i) the power, direct or indirect, to cause the + * direction or management of such entity, whether by contract or + * otherwise, or (ii) ownership of fifty percent (50%) or more of the + * outstanding shares, or (iii) beneficial ownership of such entity. + * + * "You" (or "Your") shall mean an individual or Legal Entity + * exercising permissions granted by this License. + * + * "Source" form shall mean the preferred form for making modifications, + * including but not limited to software source code, documentation + * source, and configuration files. + * + * "Object" form shall mean any form resulting from mechanical + * transformation or translation of a Source form, including but + * not limited to compiled object code, generated documentation, + * and conversions to other media types. + * + * "Work" shall mean the work of authorship, whether in Source or + * Object form, made available under the License, as indicated by a + * copyright notice that is included in or attached to the work + * (an example is provided in the Appendix below). + * + * "Derivative Works" shall mean any work, whether in Source or Object + * form, that is based on (or derived from) the Work and for which the + * editorial revisions, annotations, elaborations, or other modifications + * represent, as a whole, an original work of authorship. For the purposes + * of this License, Derivative Works shall not include works that remain + * separable from, or merely link (or bind by name) to the interfaces of, + * the Work and Derivative Works thereof. + * + * "Contribution" shall mean any work of authorship, including + * the original version of the Work and any modifications or additions + * to that Work or Derivative Works thereof, that is intentionally + * submitted to Licensor for inclusion in the Work by the copyright owner + * or by an individual or Legal Entity authorized to submit on behalf of + * the copyright owner. For the purposes of this definition, "submitted" + * means any form of electronic, verbal, or written communication sent + * to the Licensor or its representatives, including but not limited to + * communication on electronic mailing lists, source code control systems, + * and issue tracking systems that are managed by, or on behalf of, the + * Licensor for the purpose of discussing and improving the Work, but + * excluding communication that is conspicuously marked or otherwise + * designated in writing by the copyright owner as "Not a Contribution." + * + * "Contributor" shall mean Licensor and any individual or Legal Entity + * on behalf of whom a Contribution has been received by Licensor and + * subsequently incorporated within the Work. + * + * 2. Grant of Copyright License. Subject to the terms and conditions of + * this License, each Contributor hereby grants to You a perpetual, + * worldwide, non-exclusive, no-charge, royalty-free, irrevocable + * copyright license to reproduce, prepare Derivative Works of, + * publicly display, publicly perform, sublicense, and distribute the + * Work and such Derivative Works in Source or Object form. + * + * 3. Grant of Patent License. Subject to the terms and conditions of + * this License, each Contributor hereby grants to You a perpetual, + * worldwide, non-exclusive, no-charge, royalty-free, irrevocable + * (except as stated in this section) patent license to make, have made, + * use, offer to sell, sell, import, and otherwise transfer the Work, + * where such license applies only to those patent claims licensable + * by such Contributor that are necessarily infringed by their + * Contribution(s) alone or by combination of their Contribution(s) + * with the Work to which such Contribution(s) was submitted. If You + * institute patent litigation against any entity (including a + * cross-claim or counterclaim in a lawsuit) alleging that the Work + * or a Contribution incorporated within the Work constitutes direct + * or contributory patent infringement, then any patent licenses + * granted to You under this License for that Work shall terminate + * as of the date such litigation is filed. + * + * 4. Redistribution. You may reproduce and distribute copies of the + * Work or Derivative Works thereof in any medium, with or without + * modifications, and in Source or Object form, provided that You + * meet the following conditions: + * + * (a) You must give any other recipients of the Work or + * Derivative Works a copy of this License; and + * + * (b) You must cause any modified files to carry prominent notices + * stating that You changed the files; and + * + * (c) You must retain, in the Source form of any Derivative Works + * that You distribute, all copyright, patent, trademark, and + * attribution notices from the Source form of the Work, + * excluding those notices that do not pertain to any part of + * the Derivative Works; and + * + * (d) If the Work includes a "NOTICE" text file as part of its + * distribution, then any Derivative Works that You distribute must + * include a readable copy of the attribution notices contained + * within such NOTICE file, excluding those notices that do not + * pertain to any part of the Derivative Works, in at least one + * of the following places: within a NOTICE text file distributed + * as part of the Derivative Works; within the Source form or + * documentation, if provided along with the Derivative Works; or, + * within a display generated by the Derivative Works, if and + * wherever such third-party notices normally appear. The contents + * of the NOTICE file are for informational purposes only and + * do not modify the License. You may add Your own attribution + * notices within Derivative Works that You distribute, alongside + * or as an addendum to the NOTICE text from the Work, provided + * that such additional attribution notices cannot be construed + * as modifying the License. + * + * You may add Your own copyright statement to Your modifications and + * may provide additional or different license terms and conditions + * for use, reproduction, or distribution of Your modifications, or + * for any such Derivative Works as a whole, provided Your use, + * reproduction, and distribution of the Work otherwise complies with + * the conditions stated in this License. + * + * 5. Submission of Contributions. Unless You explicitly state otherwise, + * any Contribution intentionally submitted for inclusion in the Work + * by You to the Licensor shall be under the terms and conditions of + * this License, without any additional terms or conditions. + * Notwithstanding the above, nothing herein shall supersede or modify + * the terms of any separate license agreement you may have executed + * with Licensor regarding such Contributions. + * + * 6. Trademarks. This License does not grant permission to use the trade + * names, trademarks, service marks, or product names of the Licensor, + * except as required for reasonable and customary use in describing the + * origin of the Work and reproducing the content of the NOTICE file. + * + * 7. Disclaimer of Warranty. Unless required by applicable law or + * agreed to in writing, Licensor provides the Work (and each + * Contributor provides its Contributions) on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied, including, without limitation, any warranties or conditions + * of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + * PARTICULAR PURPOSE. You are solely responsible for determining the + * appropriateness of using or redistributing the Work and assume any + * risks associated with Your exercise of permissions under this License. + * + * 8. Limitation of Liability. In no event and under no legal theory, + * whether in tort (including negligence), contract, or otherwise, + * unless required by applicable law (such as deliberate and grossly + * negligent acts) or agreed to in writing, shall any Contributor be + * liable to You for damages, including any direct, indirect, special, + * incidental, or consequential damages of any character arising as a + * result of this License or out of the use or inability to use the + * Work (including but not limited to damages for loss of goodwill, + * work stoppage, computer failure or malfunction, or any and all + * other commercial damages or losses), even if such Contributor + * has been advised of the possibility of such damages. + * + * 9. Accepting Warranty or Additional Liability. While redistributing + * the Work or Derivative Works thereof, You may choose to offer, + * and charge a fee for, acceptance of support, warranty, indemnity, + * or other liability obligations and/or rights consistent with this + * License. However, in accepting such obligations, You may act only + * on Your own behalf and on Your sole responsibility, not on behalf + * of any other Contributor, and only if You agree to indemnify, + * defend, and hold each Contributor harmless for any liability + * incurred by, or claims asserted against, such Contributor by reason + * of your accepting any such warranty or additional liability. + * + * END OF TERMS AND CONDITIONS + * + * APPENDIX: How to apply the Apache License to your work. + * + * To apply the Apache License to your work, attach the following + * boilerplate notice, with the fields enclosed by brackets "{}" + * replaced with your own identifying information. (Don't include + * the brackets!) The text should be enclosed in the appropriate + * comment syntax for the file format. We also recommend that a + * file or class name and description of purpose be included on the + * same "printed page" as the copyright notice for easier + * identification within third-party archives. + * + * Copyright 2014 Edgar Espina + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jooby.json; + +import com.google.gson.Gson; +import org.jooby.MediaType; + +class GsonRawRenderer extends GsonRenderer { + + public GsonRawRenderer(MediaType type, Gson gson) { + super(type, gson); + } + + @Override public void render(Object value, Context ctx) throws Exception { + if (value instanceof CharSequence) { + ctx.type(type).send(value.toString()); + } else { + super.render(value, ctx); + } + } +} diff --git a/modules/jooby-gson/src/main/java/org/jooby/json/GsonRenderer.java b/modules/jooby-gson/src/main/java/org/jooby/json/GsonRenderer.java index 75e17d283b..0f08b823a6 100644 --- a/modules/jooby-gson/src/main/java/org/jooby/json/GsonRenderer.java +++ b/modules/jooby-gson/src/main/java/org/jooby/json/GsonRenderer.java @@ -212,7 +212,7 @@ class GsonRenderer implements Renderer { - private final MediaType type; + protected final MediaType type; private final Gson gson; diff --git a/modules/jooby-gson/src/main/java/org/jooby/json/Gzon.java b/modules/jooby-gson/src/main/java/org/jooby/json/Gzon.java index 24c66f2ee3..5c5f69e496 100644 --- a/modules/jooby-gson/src/main/java/org/jooby/json/Gzon.java +++ b/modules/jooby-gson/src/main/java/org/jooby/json/Gzon.java @@ -278,6 +278,8 @@ public class Gzon implements Jooby.Module { private BiConsumer configurer; + private boolean raw; + /** * Creates a new {@link Gson}. * @@ -351,8 +353,27 @@ public void configure(final Env env, final Config config, final Binder binder) { Multibinder.newSetBinder(binder, Parser.class).addBinding() .toInstance(new GsonParser(type, gson)); - Multibinder.newSetBinder(binder, Renderer.class).addBinding() - .toInstance(new GsonRenderer(type, gson)); + GsonRenderer renderer = raw ? new GsonRawRenderer(type, gson) : new GsonRenderer(type, gson); + + Multibinder.newSetBinder(binder, Renderer.class).addBinding().toInstance(renderer); + } + + /** + * Add support raw string json responses: + * + *
{@code
+   * {
+   *   get("/raw", () -> {
+   *     return "{\"raw\": \"json\"}";
+   *   });
+   * }
+   * }
+ * + * @return This module. + */ + public Gzon raw() { + raw = true; + return this; } } diff --git a/modules/jooby-gson/src/test/java/org/jooby/json/GsonRendererTest.java b/modules/jooby-gson/src/test/java/org/jooby/json/GsonRendererTest.java index e5be910a09..92d66cfe91 100644 --- a/modules/jooby-gson/src/test/java/org/jooby/json/GsonRendererTest.java +++ b/modules/jooby-gson/src/test/java/org/jooby/json/GsonRendererTest.java @@ -39,6 +39,43 @@ public void render() throws Exception { }); } + @Test + public void rawWithCharSequence() throws Exception { + String value = "{\"foo\":\"bar\"}"; + new MockUnit(Gson.class, Renderer.Context.class) + .expect(unit -> { + Context ctx = unit.get(Renderer.Context.class); + expect(ctx.type(MediaType.json)).andReturn(ctx); + ctx.send(value); + }) + .run(unit -> { + new GsonRawRenderer(MediaType.json, unit.get(Gson.class)) + .render(value, unit.get(Renderer.Context.class)); + }, unit -> { + }); + } + + @Test + public void rawWithObject() throws Exception { + Object value = new GsonRendererTest(); + new MockUnit(Gson.class, Renderer.Context.class) + .expect(unit -> { + Context ctx = unit.get(Renderer.Context.class); + expect(ctx.accepts(MediaType.json)).andReturn(true); + expect(ctx.type(MediaType.json)).andReturn(ctx); + ctx.send("{}"); + }) + .expect(unit -> { + Gson gson = unit.get(Gson.class); + expect(gson.toJson(value)).andReturn("{}"); + }) + .run(unit -> { + new GsonRawRenderer(MediaType.json, unit.get(Gson.class)) + .render(value, unit.get(Renderer.Context.class)); + }, unit -> { + }); + } + @Test public void renderSkip() throws Exception { Object value = new GsonRendererTest(); diff --git a/modules/jooby-gson/src/test/java/org/jooby/json/GzonTest.java b/modules/jooby-gson/src/test/java/org/jooby/json/GzonTest.java index 675fc78284..ef6713998e 100644 --- a/modules/jooby-gson/src/test/java/org/jooby/json/GzonTest.java +++ b/modules/jooby-gson/src/test/java/org/jooby/json/GzonTest.java @@ -70,6 +70,17 @@ public void defaults() throws Exception { }); } + @Test + public void raw() throws Exception { + new MockUnit(Env.class, Config.class, Binder.class, Gson.class) + .expect(body) + .run(unit -> { + new Gzon() + .raw() + .configure(unit.get(Env.class), unit.get(Config.class), unit.get(Binder.class)); + }); + } + @SuppressWarnings("unchecked") @Test public void withCallback() throws Exception { diff --git a/modules/jooby-guava-cache/README.md b/modules/jooby-guava-cache/README.md index c289126e79..31b6c74066 100644 --- a/modules/jooby-guava-cache/README.md +++ b/modules/jooby-guava-cache/README.md @@ -1,5 +1,5 @@ -[![Maven Central](https://maven-badges.herokuapp.com/maven-central/org.jooby/jooby-guava-cache/badge.svg)](https://maven-badges.herokuapp.com/maven-central/org.jooby/jooby-guava-cache) -[![javadoc](https://javadoc.io/badge/org.jooby/jooby-guava-cache.svg)](https://javadoc.io/doc/org.jooby/jooby-guava-cache/1.5.0) +[![Maven](https://img.shields.io/maven-metadata/v/http/central.maven.org/maven2/org/jooby/jooby-guava-cache/maven-metadata.xml.svg)](http://mvnrepository.com/artifact/org.jooby/jooby-guava-cache/1.6.6) +[![javadoc](https://javadoc.io/badge/org.jooby/jooby-guava-cache.svg)](https://javadoc.io/doc/org.jooby/jooby-guava-cache/1.6.6) [![jooby-guava-cache website](https://img.shields.io/badge/jooby-guava-cache-brightgreen.svg)](http://jooby.org/doc/guava-cache) # guava-cache @@ -15,7 +15,7 @@ Provides cache solution and session storage via:
Hibernate ORM org.jooby jooby-hbm - 1.5.0 + 1.6.6 ``` diff --git a/modules/jooby-hbm/pom.xml b/modules/jooby-hbm/pom.xml index 525924ec26..780e556d16 100644 --- a/modules/jooby-hbm/pom.xml +++ b/modules/jooby-hbm/pom.xml @@ -5,7 +5,7 @@ org.jooby modules - 1.5.1-SNAPSHOT + 1.6.9 4.0.0 @@ -37,10 +37,16 @@ ${project.version}
+ + + javax.enterprise + cdi-api + + org.hibernate - hibernate-entitymanager + hibernate-core diff --git a/modules/jooby-hbm/src/main/java/org/jooby/hbm/Hbm.java b/modules/jooby-hbm/src/main/java/org/jooby/hbm/Hbm.java index d97f43a045..87edae19a8 100644 --- a/modules/jooby-hbm/src/main/java/org/jooby/hbm/Hbm.java +++ b/modules/jooby-hbm/src/main/java/org/jooby/hbm/Hbm.java @@ -209,6 +209,7 @@ import com.typesafe.config.Config; import com.typesafe.config.ConfigFactory; import org.hibernate.Session; +import org.hibernate.SessionBuilder; import org.hibernate.SessionFactory; import org.hibernate.boot.Metadata; import org.hibernate.boot.MetadataSources; @@ -222,18 +223,13 @@ import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.event.service.spi.EventListenerRegistry; import org.hibernate.event.spi.EventType; -import org.hibernate.jpa.event.spi.JpaIntegrator; import org.hibernate.service.spi.ServiceRegistryImplementor; import org.jooby.Env; import org.jooby.Env.ServiceKey; import org.jooby.Jooby; import org.jooby.Registry; import org.jooby.Route; -import org.jooby.internal.hbm.GuiceBeanManager; -import org.jooby.internal.hbm.OpenSessionInView; -import org.jooby.internal.hbm.ScanEnvImpl; -import org.jooby.internal.hbm.SessionProvider; -import org.jooby.internal.hbm.UnitOfWorkProvider; +import org.jooby.internal.hbm.*; import org.jooby.jdbc.Jdbc; import javax.inject.Provider; @@ -535,6 +531,8 @@ public class Hbm implements Jooby.Module { private BiConsumer sf = NOOP; + private BiConsumer sb = NOOP; + /** * Creates a new {@link Hbm} module. * @@ -745,6 +743,28 @@ public Hbm doWithSessionFactoryBuilder( return this; } + /** + * Configurer callback to apply advanced configuration while bootstrapping hibernate: + * + * @param configurer Configurer callback. + * @return This module + */ + public Hbm doWithSessionBuilder( + final BiConsumer configurer) { + this.sb = configurer; + return this; + } + + /** + * Configurer callback to apply advanced configuration while bootstrapping hibernate: + * + * @param configurer Configurer callback. + * @return This module + */ + public Hbm doWithSessionBuilder(final Consumer configurer) { + return doWithSessionBuilder((builder, conf) -> configurer.accept(builder)); + } + @Override public void configure(final Env env, final Config conf, final Binder binder) { Key dskey = Key.get(DataSource.class, Names.named(name)); @@ -752,7 +772,6 @@ public void configure(final Env env, final Config conf, final Binder binder) { .orElseThrow(() -> new NoSuchElementException("DataSource missing: " + dskey)); BootstrapServiceRegistryBuilder bsrb = new BootstrapServiceRegistryBuilder(); - bsrb.applyIntegrator(new JpaIntegrator()); this.bsrb.accept(bsrb, conf); @@ -767,7 +786,10 @@ public void configure(final Env env, final Config conf, final Binder binder) { this.ssrb.accept(ssrb, conf); ssrb.applySetting(AvailableSettings.DATASOURCE, ds); - ssrb.applySetting(org.hibernate.jpa.AvailableSettings.DELAY_CDI_ACCESS, true); + ssrb.applySetting(org.hibernate.cfg.AvailableSettings.DELAY_CDI_ACCESS, true); + + CompletableFuture registry = new CompletableFuture<>(); + ssrb.applySetting(org.hibernate.cfg.AvailableSettings.CDI_BEAN_MANAGER, GuiceBeanManager.beanManager(registry)); StandardServiceRegistry serviceRegistry = ssrb.build(); @@ -790,13 +812,12 @@ public void configure(final Env env, final Config conf, final Binder binder) { this.sfb.accept(sfb, conf); sfb.applyName(name); - CompletableFuture registry = new CompletableFuture<>(); - sfb.applyBeanManager(GuiceBeanManager.beanManager(registry)); - SessionFactory sessionFactory = sfb.build(); this.sf.accept(sessionFactory, conf); - Provider session = new SessionProvider(sessionFactory); + SessionBuilderConfigurer sbc = builder -> this.sb.accept(builder, conf); + + Provider session = new SessionProvider(sessionFactory, sbc); ServiceKey serviceKey = env.serviceKey(); serviceKey.generate(SessionFactory.class, name, @@ -811,7 +832,7 @@ public void configure(final Env env, final Config conf, final Binder binder) { k -> binder.bind(k).toProvider(session)); /** Unit of work . */ - Provider uow = new UnitOfWorkProvider(sessionFactory); + Provider uow = new UnitOfWorkProvider(sessionFactory, sbc); serviceKey.generate(UnitOfWork.class, name, k -> binder.bind(k).toProvider(uow)); diff --git a/modules/jooby-hbm/src/main/java/org/jooby/internal/hbm/OpenSessionInView.java b/modules/jooby-hbm/src/main/java/org/jooby/internal/hbm/OpenSessionInView.java index 6a11d8bf3a..06cbd68c71 100644 --- a/modules/jooby-hbm/src/main/java/org/jooby/internal/hbm/OpenSessionInView.java +++ b/modules/jooby-hbm/src/main/java/org/jooby/internal/hbm/OpenSessionInView.java @@ -215,15 +215,25 @@ public class OpenSessionInView implements Filter { @Override public void handle(final Request req, final Response rsp, final Chain chain) throws Throwable { RootUnitOfWork uow = (RootUnitOfWork) req.require(UnitOfWork.class); - // start transaction - uow.begin(); - rsp.after(after(uow)); + try { + // start transaction + uow.begin(); + + rsp.after(after(uow)); - rsp.complete(complete(uow)); + rsp.complete(complete(uow)); - // move next - chain.next(req, rsp); + // move next + chain.next(req, rsp); + } catch (Throwable x) { + try { + uow.setRollbackOnly().end(); + } catch (Throwable suppressed) { + x.addSuppressed(suppressed); + } + throw x; + } } private static Route.Complete complete(final RootUnitOfWork uow) { diff --git a/modules/jooby-hbm/src/main/java/org/jooby/internal/hbm/RootUnitOfWork.java b/modules/jooby-hbm/src/main/java/org/jooby/internal/hbm/RootUnitOfWork.java index bc0eca95d0..c14837913a 100644 --- a/modules/jooby-hbm/src/main/java/org/jooby/internal/hbm/RootUnitOfWork.java +++ b/modules/jooby-hbm/src/main/java/org/jooby/internal/hbm/RootUnitOfWork.java @@ -243,15 +243,15 @@ public UnitOfWork commit() { return this; } if (!readOnly) { - log.debug("flusing session: {}", oid(session)); + log.debug("flushing session: {}", oid(session)); session.flush(); } else { - log.debug("flusing ignored on read-only session: {}", oid(session)); + log.debug("flushing ignored on read-only session: {}", oid(session)); } active(session, trx -> { - log.debug("commiting transaction: {}(trx@{})", oid(session), oid(trx)); + log.debug("committing transaction: {}(trx@{})", oid(session), oid(trx)); trx.commit(); - }, trx -> log.warn("unable to commit inactive transaction: {}(trx@{})", oid(session), oid(trx))); + }, trx -> log.debug("unable to commit inactive transaction: {}(trx@{})", oid(session), oid(trx))); return this; } @@ -277,7 +277,7 @@ public UnitOfWork rollback() { active(session, trx -> { log.debug("rollback transaction: {}(trx@{})", oid(session), oid(trx)); trx.rollback(); - }, trx -> log.warn("unable to rollback inactive transaction: {}(trx@{})", oid(session), oid(trx))); + }, trx -> log.debug("unable to rollback inactive transaction: {}(trx@{})", oid(session), oid(trx))); return this; } @@ -303,16 +303,19 @@ public void end() { commit(); } } finally { - if (readOnly) { - setConnectionReadOnly(false); - } + try { + if (readOnly) { + setConnectionReadOnly(false); + } - String sessionId = oid(session); - log.debug("closing session: {}", sessionId); - Try.run(session::close) - .onFailure(x -> log.error("session.close() resulted in exception: {}", sessionId, x)) - .onSuccess(() -> log.debug("session closed: {}", sessionId)); - unbind(session.getSessionFactory()); + String sessionId = oid(session); + log.debug("closing session: {}", sessionId); + Try.run(session::close) + .onFailure(x -> log.error("session.close() resulted in exception: {}", sessionId, x)) + .onSuccess(() -> log.debug("session closed: {}", sessionId)); + } finally { + unbind(session.getSessionFactory()); + } } } diff --git a/modules/jooby-hbm/src/main/java/org/jooby/internal/hbm/SessionBuilderConfigurer.java b/modules/jooby-hbm/src/main/java/org/jooby/internal/hbm/SessionBuilderConfigurer.java new file mode 100644 index 0000000000..878748d106 --- /dev/null +++ b/modules/jooby-hbm/src/main/java/org/jooby/internal/hbm/SessionBuilderConfigurer.java @@ -0,0 +1,219 @@ +/** + * Apache License + * Version 2.0, January 2004 + * http://www.apache.org/licenses/ + * + * TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + * + * 1. Definitions. + * + * "License" shall mean the terms and conditions for use, reproduction, + * and distribution as defined by Sections 1 through 9 of this document. + * + * "Licensor" shall mean the copyright owner or entity authorized by + * the copyright owner that is granting the License. + * + * "Legal Entity" shall mean the union of the acting entity and all + * other entities that control, are controlled by, or are under common + * control with that entity. For the purposes of this definition, + * "control" means (i) the power, direct or indirect, to cause the + * direction or management of such entity, whether by contract or + * otherwise, or (ii) ownership of fifty percent (50%) or more of the + * outstanding shares, or (iii) beneficial ownership of such entity. + * + * "You" (or "Your") shall mean an individual or Legal Entity + * exercising permissions granted by this License. + * + * "Source" form shall mean the preferred form for making modifications, + * including but not limited to software source code, documentation + * source, and configuration files. + * + * "Object" form shall mean any form resulting from mechanical + * transformation or translation of a Source form, including but + * not limited to compiled object code, generated documentation, + * and conversions to other media types. + * + * "Work" shall mean the work of authorship, whether in Source or + * Object form, made available under the License, as indicated by a + * copyright notice that is included in or attached to the work + * (an example is provided in the Appendix below). + * + * "Derivative Works" shall mean any work, whether in Source or Object + * form, that is based on (or derived from) the Work and for which the + * editorial revisions, annotations, elaborations, or other modifications + * represent, as a whole, an original work of authorship. For the purposes + * of this License, Derivative Works shall not include works that remain + * separable from, or merely link (or bind by name) to the interfaces of, + * the Work and Derivative Works thereof. + * + * "Contribution" shall mean any work of authorship, including + * the original version of the Work and any modifications or additions + * to that Work or Derivative Works thereof, that is intentionally + * submitted to Licensor for inclusion in the Work by the copyright owner + * or by an individual or Legal Entity authorized to submit on behalf of + * the copyright owner. For the purposes of this definition, "submitted" + * means any form of electronic, verbal, or written communication sent + * to the Licensor or its representatives, including but not limited to + * communication on electronic mailing lists, source code control systems, + * and issue tracking systems that are managed by, or on behalf of, the + * Licensor for the purpose of discussing and improving the Work, but + * excluding communication that is conspicuously marked or otherwise + * designated in writing by the copyright owner as "Not a Contribution." + * + * "Contributor" shall mean Licensor and any individual or Legal Entity + * on behalf of whom a Contribution has been received by Licensor and + * subsequently incorporated within the Work. + * + * 2. Grant of Copyright License. Subject to the terms and conditions of + * this License, each Contributor hereby grants to You a perpetual, + * worldwide, non-exclusive, no-charge, royalty-free, irrevocable + * copyright license to reproduce, prepare Derivative Works of, + * publicly display, publicly perform, sublicense, and distribute the + * Work and such Derivative Works in Source or Object form. + * + * 3. Grant of Patent License. Subject to the terms and conditions of + * this License, each Contributor hereby grants to You a perpetual, + * worldwide, non-exclusive, no-charge, royalty-free, irrevocable + * (except as stated in this section) patent license to make, have made, + * use, offer to sell, sell, import, and otherwise transfer the Work, + * where such license applies only to those patent claims licensable + * by such Contributor that are necessarily infringed by their + * Contribution(s) alone or by combination of their Contribution(s) + * with the Work to which such Contribution(s) was submitted. If You + * institute patent litigation against any entity (including a + * cross-claim or counterclaim in a lawsuit) alleging that the Work + * or a Contribution incorporated within the Work constitutes direct + * or contributory patent infringement, then any patent licenses + * granted to You under this License for that Work shall terminate + * as of the date such litigation is filed. + * + * 4. Redistribution. You may reproduce and distribute copies of the + * Work or Derivative Works thereof in any medium, with or without + * modifications, and in Source or Object form, provided that You + * meet the following conditions: + * + * (a) You must give any other recipients of the Work or + * Derivative Works a copy of this License; and + * + * (b) You must cause any modified files to carry prominent notices + * stating that You changed the files; and + * + * (c) You must retain, in the Source form of any Derivative Works + * that You distribute, all copyright, patent, trademark, and + * attribution notices from the Source form of the Work, + * excluding those notices that do not pertain to any part of + * the Derivative Works; and + * + * (d) If the Work includes a "NOTICE" text file as part of its + * distribution, then any Derivative Works that You distribute must + * include a readable copy of the attribution notices contained + * within such NOTICE file, excluding those notices that do not + * pertain to any part of the Derivative Works, in at least one + * of the following places: within a NOTICE text file distributed + * as part of the Derivative Works; within the Source form or + * documentation, if provided along with the Derivative Works; or, + * within a display generated by the Derivative Works, if and + * wherever such third-party notices normally appear. The contents + * of the NOTICE file are for informational purposes only and + * do not modify the License. You may add Your own attribution + * notices within Derivative Works that You distribute, alongside + * or as an addendum to the NOTICE text from the Work, provided + * that such additional attribution notices cannot be construed + * as modifying the License. + * + * You may add Your own copyright statement to Your modifications and + * may provide additional or different license terms and conditions + * for use, reproduction, or distribution of Your modifications, or + * for any such Derivative Works as a whole, provided Your use, + * reproduction, and distribution of the Work otherwise complies with + * the conditions stated in this License. + * + * 5. Submission of Contributions. Unless You explicitly state otherwise, + * any Contribution intentionally submitted for inclusion in the Work + * by You to the Licensor shall be under the terms and conditions of + * this License, without any additional terms or conditions. + * Notwithstanding the above, nothing herein shall supersede or modify + * the terms of any separate license agreement you may have executed + * with Licensor regarding such Contributions. + * + * 6. Trademarks. This License does not grant permission to use the trade + * names, trademarks, service marks, or product names of the Licensor, + * except as required for reasonable and customary use in describing the + * origin of the Work and reproducing the content of the NOTICE file. + * + * 7. Disclaimer of Warranty. Unless required by applicable law or + * agreed to in writing, Licensor provides the Work (and each + * Contributor provides its Contributions) on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied, including, without limitation, any warranties or conditions + * of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + * PARTICULAR PURPOSE. You are solely responsible for determining the + * appropriateness of using or redistributing the Work and assume any + * risks associated with Your exercise of permissions under this License. + * + * 8. Limitation of Liability. In no event and under no legal theory, + * whether in tort (including negligence), contract, or otherwise, + * unless required by applicable law (such as deliberate and grossly + * negligent acts) or agreed to in writing, shall any Contributor be + * liable to You for damages, including any direct, indirect, special, + * incidental, or consequential damages of any character arising as a + * result of this License or out of the use or inability to use the + * Work (including but not limited to damages for loss of goodwill, + * work stoppage, computer failure or malfunction, or any and all + * other commercial damages or losses), even if such Contributor + * has been advised of the possibility of such damages. + * + * 9. Accepting Warranty or Additional Liability. While redistributing + * the Work or Derivative Works thereof, You may choose to offer, + * and charge a fee for, acceptance of support, warranty, indemnity, + * or other liability obligations and/or rights consistent with this + * License. However, in accepting such obligations, You may act only + * on Your own behalf and on Your sole responsibility, not on behalf + * of any other Contributor, and only if You agree to indemnify, + * defend, and hold each Contributor harmless for any liability + * incurred by, or claims asserted against, such Contributor by reason + * of your accepting any such warranty or additional liability. + * + * END OF TERMS AND CONDITIONS + * + * APPENDIX: How to apply the Apache License to your work. + * + * To apply the Apache License to your work, attach the following + * boilerplate notice, with the fields enclosed by brackets "{}" + * replaced with your own identifying information. (Don't include + * the brackets!) The text should be enclosed in the appropriate + * comment syntax for the file format. We also recommend that a + * file or class name and description of purpose be included on the + * same "printed page" as the copyright notice for easier + * identification within third-party archives. + * + * Copyright 2014 Edgar Espina + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jooby.internal.hbm; + +import org.hibernate.Session; +import org.hibernate.SessionBuilder; +import org.hibernate.SessionFactory; + +public interface SessionBuilderConfigurer { + + void configure(SessionBuilder sessionBuilder); + + default Session apply(SessionFactory sessionFactory) { + final SessionBuilder sb = sessionFactory.withOptions(); + configure(sb); + return sb.openSession(); + } +} \ No newline at end of file diff --git a/modules/jooby-hbm/src/main/java/org/jooby/internal/hbm/SessionProvider.java b/modules/jooby-hbm/src/main/java/org/jooby/internal/hbm/SessionProvider.java index ed68f6dd84..2d705412b3 100644 --- a/modules/jooby-hbm/src/main/java/org/jooby/internal/hbm/SessionProvider.java +++ b/modules/jooby-hbm/src/main/java/org/jooby/internal/hbm/SessionProvider.java @@ -212,14 +212,16 @@ public class SessionProvider implements Provider { private final SessionFactory sf; + private final SessionBuilderConfigurer sbc; - public SessionProvider(final SessionFactory sf) { + public SessionProvider(final SessionFactory sf, final SessionBuilderConfigurer sbc) { this.sf = sf; + this.sbc = sbc; } @Override public Session get() { - return ManagedSessionContext.hasBind(sf) ? sf.getCurrentSession() : sf.openSession(); + return ManagedSessionContext.hasBind(sf) ? sf.getCurrentSession() : sbc.apply(sf); } } diff --git a/modules/jooby-hbm/src/main/java/org/jooby/internal/hbm/UnitOfWorkProvider.java b/modules/jooby-hbm/src/main/java/org/jooby/internal/hbm/UnitOfWorkProvider.java index 6910abf5af..520fcf6389 100644 --- a/modules/jooby-hbm/src/main/java/org/jooby/internal/hbm/UnitOfWorkProvider.java +++ b/modules/jooby-hbm/src/main/java/org/jooby/internal/hbm/UnitOfWorkProvider.java @@ -212,9 +212,11 @@ public class UnitOfWorkProvider implements Provider { private final SessionFactory sf; + private final SessionBuilderConfigurer sbc; - public UnitOfWorkProvider(final SessionFactory sf) { + public UnitOfWorkProvider(final SessionFactory sf, final SessionBuilderConfigurer sbc) { this.sf = sf; + this.sbc = sbc; } @Override @@ -222,7 +224,7 @@ public UnitOfWork get() { if (ManagedSessionContext.hasBind(sf)) { return new ChildUnitOfWork(sf.getCurrentSession()); } else { - return new RootUnitOfWork(sf.openSession()); + return new RootUnitOfWork(sbc.apply(sf)); } } diff --git a/modules/jooby-hbm/src/test/java/org/jooby/hbm/HbmTest.java b/modules/jooby-hbm/src/test/java/org/jooby/hbm/HbmTest.java index ddc4f4c5ca..c0f7b95710 100644 --- a/modules/jooby-hbm/src/test/java/org/jooby/hbm/HbmTest.java +++ b/modules/jooby-hbm/src/test/java/org/jooby/hbm/HbmTest.java @@ -13,8 +13,9 @@ import com.zaxxer.hikari.HikariConfig; import com.zaxxer.hikari.HikariDataSource; import hbm5.Beer; -import static org.easymock.EasyMock.expect; + import org.hibernate.Session; +import org.hibernate.SessionBuilder; import org.hibernate.SessionFactory; import org.hibernate.boot.Metadata; import org.hibernate.boot.MetadataBuilder; @@ -27,24 +28,22 @@ import org.hibernate.boot.registry.StandardServiceRegistry; import org.hibernate.boot.registry.StandardServiceRegistryBuilder; import org.hibernate.cfg.AvailableSettings; +import org.hibernate.engine.spi.SessionBuilderImplementor; import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.event.service.spi.EventListenerRegistry; import org.hibernate.event.spi.EventType; import org.hibernate.event.spi.PostLoadEventListener; import org.hibernate.integrator.spi.Integrator; -import org.hibernate.jpa.event.spi.JpaIntegrator; import org.hibernate.service.spi.ServiceRegistryImplementor; import org.jooby.Env; import org.jooby.Env.ServiceKey; import org.jooby.Registry; import org.jooby.funzy.Throwing; -import org.jooby.internal.hbm.GuiceBeanManager; -import org.jooby.internal.hbm.OpenSessionInView; -import org.jooby.internal.hbm.ScanEnvImpl; -import org.jooby.internal.hbm.SessionProvider; -import org.jooby.internal.hbm.UnitOfWorkProvider; +import org.jooby.internal.hbm.*; import org.jooby.test.MockUnit; import org.jooby.test.MockUnit.Block; + +import static org.easymock.EasyMock.*; import static org.junit.Assert.assertEquals; import org.junit.Test; import org.junit.runner.RunWith; @@ -67,7 +66,7 @@ import java.util.stream.Collectors; @RunWith(PowerMockRunner.class) -@PrepareForTest({Hbm.class, BootstrapServiceRegistryBuilder.class, JpaIntegrator.class, +@PrepareForTest({Hbm.class, BootstrapServiceRegistryBuilder.class, MetadataSources.class, CompletableFuture.class, GuiceBeanManager.class, SessionProvider.class, OpenSessionInView.class}) public class HbmTest { @@ -77,11 +76,6 @@ public class HbmTest { .build(); unit.registerMock(BootstrapServiceRegistryBuilder.class, bsrb); - JpaIntegrator jpa = unit.constructor(JpaIntegrator.class) - .build(); - - expect(bsrb.applyIntegrator(jpa)).andReturn(bsrb); - BootstrapServiceRegistry bsr = unit.mock(BootstrapServiceRegistry.class); unit.registerMock(BootstrapServiceRegistry.class, bsr); @@ -706,6 +700,53 @@ public void doWithSessionFactoryBuilder() throws Exception { }); } + @Test + public void doWithSessionBuilder() throws Exception { + new MockUnit(Env.class, Config.class, Binder.class, Integrator.class, SessionBuilderImplementor.class) + .expect(env("prod")) + .expect(bsrb) + .expect(ssrb("none")) + .expect(applySettins(ImmutableMap.of( + AvailableSettings.SESSION_FACTORY_NAME_IS_JNDI, false, + AvailableSettings.SCANNER_DISCOVERY, "class", + AvailableSettings.CURRENT_SESSION_CONTEXT_CLASS, "managed"))) + .expect(applyDataSource) + .expect(metadataSources()) + .expect(metadataBuilder()) + .expect(sessionFactoryBuilder("db")) + .expect(beanManager()) + .expect(bind(null, SessionFactory.class)) + .expect(bind("db", SessionFactory.class)) + .expect(bind(null, EntityManagerFactory.class)) + .expect(bind("db", EntityManagerFactory.class)) + .expect(sessionProvider()) + .expect(bind(null, Session.class, SessionProvider.class)) + .expect(bind("db", Session.class, SessionProvider.class)) + .expect(bind(null, EntityManager.class, SessionProvider.class)) + .expect(bind("db", EntityManager.class, SessionProvider.class)) + .expect(unitOfWork()) + .expect(bind(null, UnitOfWork.class, UnitOfWorkProvider.class)) + .expect(bind("db", UnitOfWork.class, UnitOfWorkProvider.class)) + .expect(onStart) + .expect(onStop) + .expect(unit -> { + SessionBuilder builder = unit.get(SessionBuilderImplementor.class); + expect(unit.get(SessionFactory.class).withOptions()).andReturn(builder); + expect(builder.setQueryParameterValidation(true)).andReturn(builder); + expect(builder.openSession()).andReturn(null); + }) + .run(unit -> { + new Hbm() + .doWithSessionBuilder((final SessionBuilder builder) -> { + builder.setQueryParameterValidation(true); + }) + .configure(unit.get(Env.class), config("hbm"), unit.get(Binder.class)); + + // invoke the captured object passed to the SessionProvider / UnitOfWorkProvider + unit.captured(SessionBuilderConfigurer.class).get(0).apply(unit.get(SessionFactory.class)); + }); + } + @Test(expected = ClassCastException.class) public void genericSetupCallbackShouldReportClassCastException() throws Exception { String url = "jdbc:h2:target/hbm"; @@ -872,7 +913,8 @@ private Block sessionProvider() { SessionFactory sf = unit.get(SessionFactory.class); SessionProvider sp = unit.constructor(SessionProvider.class) - .build(sf); + .args(SessionFactory.class, SessionBuilderConfigurer.class) + .build(eq(sf), unit.capture(SessionBuilderConfigurer.class)); unit.registerMock(SessionProvider.class, sp); }; @@ -883,7 +925,8 @@ private Block unitOfWork() { SessionFactory sf = unit.get(SessionFactory.class); UnitOfWorkProvider sp = unit.constructor(UnitOfWorkProvider.class) - .build(sf); + .args(SessionFactory.class, SessionBuilderConfigurer.class) + .build(eq(sf), unit.capture(SessionBuilderConfigurer.class)); unit.registerMock(UnitOfWorkProvider.class, sp); }; @@ -918,13 +961,18 @@ private Block beanManager() { return unit -> { unit.mockStatic(GuiceBeanManager.class); + StandardServiceRegistryBuilder ssrb = unit.get(StandardServiceRegistryBuilder.class); + + expect(ssrb.applySetting(org.hibernate.cfg.AvailableSettings.DELAY_CDI_ACCESS, true)) + .andReturn(ssrb); + BeanManager bm = unit.mock(BeanManager.class); unit.registerMock(BeanManager.class, bm); expect(GuiceBeanManager.beanManager(unit.capture(CompletableFuture.class))).andReturn(bm); - SessionFactoryBuilder sfb = unit.get(SessionFactoryBuilder.class); - expect(sfb.applyBeanManager(bm)).andReturn(sfb); + expect(ssrb.applySetting(org.hibernate.cfg.AvailableSettings.CDI_BEAN_MANAGER, bm)) + .andReturn(ssrb); }; } @@ -1008,8 +1056,6 @@ private Block applySettins(final Map settings) { return unit -> { StandardServiceRegistryBuilder ssrb = unit.get(StandardServiceRegistryBuilder.class); expect(ssrb.applySettings(settings)).andReturn(ssrb); - expect(ssrb.applySetting(org.hibernate.jpa.AvailableSettings.DELAY_CDI_ACCESS, true)) - .andReturn(ssrb); }; } diff --git a/modules/jooby-hbm/src/test/java/org/jooby/internal/hbm/SessionProviderTest.java b/modules/jooby-hbm/src/test/java/org/jooby/internal/hbm/SessionProviderTest.java index 19d0fb3268..69168ae986 100644 --- a/modules/jooby-hbm/src/test/java/org/jooby/internal/hbm/SessionProviderTest.java +++ b/modules/jooby-hbm/src/test/java/org/jooby/internal/hbm/SessionProviderTest.java @@ -4,8 +4,10 @@ import static org.junit.Assert.assertEquals; import org.hibernate.Session; +import org.hibernate.SessionBuilder; import org.hibernate.SessionFactory; import org.hibernate.context.internal.ManagedSessionContext; +import org.hibernate.engine.spi.SessionBuilderImplementor; import org.jooby.test.MockUnit; import org.jooby.test.MockUnit.Block; import org.junit.Test; @@ -19,13 +21,15 @@ public class SessionProviderTest { @Test public void openSession() throws Exception { - new MockUnit(SessionFactory.class, Session.class) + new MockUnit(SessionFactory.class, Session.class, SessionBuilderImplementor.class) .expect(hasBind(false)) .expect(unit -> { - expect(unit.get(SessionFactory.class).openSession()).andReturn(unit.get(Session.class)); + SessionBuilder builder = unit.get(SessionBuilderImplementor.class); + expect(unit.get(SessionFactory.class).withOptions()).andReturn(builder); + expect(builder.openSession()).andReturn(unit.get(Session.class)); }) .run(unit -> { - Session result = new SessionProvider(unit.get(SessionFactory.class)).get(); + Session result = new SessionProvider(unit.get(SessionFactory.class), b -> {}).get(); assertEquals(unit.get(Session.class), result); }); } @@ -39,7 +43,25 @@ public void currentSession() throws Exception { .andReturn(unit.get(Session.class)); }) .run(unit -> { - Session result = new SessionProvider(unit.get(SessionFactory.class)).get(); + Session result = new SessionProvider(unit.get(SessionFactory.class), b -> {}).get(); + assertEquals(unit.get(Session.class), result); + }); + } + + @Test + public void sessionBuilderConfigurer() throws Exception { + new MockUnit(SessionFactory.class, Session.class, SessionBuilderImplementor.class) + .expect(hasBind(false)) + .expect(unit -> { + SessionBuilder builder = unit.get(SessionBuilderImplementor.class); + expect(unit.get(SessionFactory.class).withOptions()).andReturn(builder); + expect(builder.setQueryParameterValidation(true)).andReturn(builder); + expect(builder.openSession()).andReturn(unit.get(Session.class)); + }) + .run(unit -> { + Session result = new SessionProvider(unit.get(SessionFactory.class), + b -> b.setQueryParameterValidation(true)).get(); + assertEquals(unit.get(Session.class), result); }); } diff --git a/modules/jooby-hbm/src/test/java/org/jooby/internal/hbm/UnitOfWorkProviderTest.java b/modules/jooby-hbm/src/test/java/org/jooby/internal/hbm/UnitOfWorkProviderTest.java index 9e2e7cb36e..ae93f901ab 100644 --- a/modules/jooby-hbm/src/test/java/org/jooby/internal/hbm/UnitOfWorkProviderTest.java +++ b/modules/jooby-hbm/src/test/java/org/jooby/internal/hbm/UnitOfWorkProviderTest.java @@ -4,8 +4,10 @@ import static org.junit.Assert.assertTrue; import org.hibernate.Session; +import org.hibernate.SessionBuilder; import org.hibernate.SessionFactory; import org.hibernate.context.internal.ManagedSessionContext; +import org.hibernate.engine.spi.SessionBuilderImplementor; import org.jooby.hbm.UnitOfWork; import org.jooby.test.MockUnit; import org.jooby.test.MockUnit.Block; @@ -21,17 +23,19 @@ public class UnitOfWorkProviderTest { @Test public void openSession() throws Exception { - new MockUnit(SessionFactory.class, Session.class) + new MockUnit(SessionFactory.class, Session.class, SessionBuilderImplementor.class) .expect(hasBind(false)) .expect(unit -> { - expect(unit.get(SessionFactory.class).openSession()).andReturn(unit.get(Session.class)); + SessionBuilder builder = unit.get(SessionBuilderImplementor.class); + expect(unit.get(SessionFactory.class).withOptions()).andReturn(builder); + expect(builder.openSession()).andReturn(unit.get(Session.class)); }) .expect(unit -> { unit.constructor(RootUnitOfWork.class) .build(unit.get(Session.class)); }) .run(unit -> { - UnitOfWork result = new UnitOfWorkProvider(unit.get(SessionFactory.class)).get(); + UnitOfWork result = new UnitOfWorkProvider(unit.get(SessionFactory.class), b -> {}).get(); assertTrue(result instanceof RootUnitOfWork); }); } @@ -49,11 +53,33 @@ public void currentSession() throws Exception { .build(unit.get(Session.class)); }) .run(unit -> { - UnitOfWork result = new UnitOfWorkProvider(unit.get(SessionFactory.class)).get(); + UnitOfWork result = new UnitOfWorkProvider(unit.get(SessionFactory.class), b -> {}).get(); assertTrue(result instanceof ChildUnitOfWork); }); } + @Test + public void sessionBuilderConfigurer() throws Exception { + new MockUnit(SessionFactory.class, Session.class, SessionBuilderImplementor.class) + .expect(hasBind(false)) + .expect(unit -> { + SessionBuilder builder = unit.get(SessionBuilderImplementor.class); + expect(unit.get(SessionFactory.class).withOptions()).andReturn(builder); + expect(builder.setQueryParameterValidation(true)).andReturn(builder); + expect(builder.openSession()).andReturn(unit.get(Session.class)); + }) + .expect(unit -> { + unit.constructor(RootUnitOfWork.class) + .build(unit.get(Session.class)); + }) + .run(unit -> { + UnitOfWork result = new UnitOfWorkProvider(unit.get(SessionFactory.class), + b -> b.setQueryParameterValidation(true)).get(); + + assertTrue(result instanceof RootUnitOfWork); + }); + } + private Block hasBind(final boolean b) { return unit -> { unit.mockStatic(ManagedSessionContext.class); diff --git a/modules/jooby-hbs/README.md b/modules/jooby-hbs/README.md index d7b4b19059..e074764b5a 100644 --- a/modules/jooby-hbs/README.md +++ b/modules/jooby-hbs/README.md @@ -1,5 +1,5 @@ -[![Maven Central](https://maven-badges.herokuapp.com/maven-central/org.jooby/jooby-hbs/badge.svg)](https://maven-badges.herokuapp.com/maven-central/org.jooby/jooby-hbs) -[![javadoc](https://javadoc.io/badge/org.jooby/jooby-hbs.svg)](https://javadoc.io/doc/org.jooby/jooby-hbs/1.5.0) +[![Maven](https://img.shields.io/maven-metadata/v/http/central.maven.org/maven2/org/jooby/jooby-hbs/maven-metadata.xml.svg)](http://mvnrepository.com/artifact/org.jooby/jooby-hbs/1.6.6) +[![javadoc](https://javadoc.io/badge/org.jooby/jooby-hbs.svg)](https://javadoc.io/doc/org.jooby/jooby-hbs/1.6.6) [![jooby-hbs website](https://img.shields.io/badge/jooby-hbs-brightgreen.svg)](http://jooby.org/doc/hbs) # handlebars @@ -16,7 +16,7 @@ Logic-less and semantic templates via [Handlebars.java](https://github.com/jknac org.jooby jooby-hbs - 1.5.0 + 1.6.6 ``` diff --git a/modules/jooby-hbs/pom.xml b/modules/jooby-hbs/pom.xml index 354950404f..5df0fe50c5 100644 --- a/modules/jooby-hbs/pom.xml +++ b/modules/jooby-hbs/pom.xml @@ -5,7 +5,7 @@ org.jooby modules - 1.5.1-SNAPSHOT + 1.6.9 4.0.0 diff --git a/modules/jooby-hbv/README.md b/modules/jooby-hbv/README.md index e079bb1d89..5dfe82fe18 100644 --- a/modules/jooby-hbv/README.md +++ b/modules/jooby-hbv/README.md @@ -1,5 +1,5 @@ -[![Maven Central](https://maven-badges.herokuapp.com/maven-central/org.jooby/jooby-hbv/badge.svg)](https://maven-badges.herokuapp.com/maven-central/org.jooby/jooby-hbv) -[![javadoc](https://javadoc.io/badge/org.jooby/jooby-hbv.svg)](https://javadoc.io/doc/org.jooby/jooby-hbv/1.5.0) +[![Maven](https://img.shields.io/maven-metadata/v/http/central.maven.org/maven2/org/jooby/jooby-hbv/maven-metadata.xml.svg)](http://mvnrepository.com/artifact/org.jooby/jooby-hbv/1.6.6) +[![javadoc](https://javadoc.io/badge/org.jooby/jooby-hbv.svg)](https://javadoc.io/doc/org.jooby/jooby-hbv/1.6.6) [![jooby-hbv website](https://img.shields.io/badge/jooby-hbv-brightgreen.svg)](http://jooby.org/doc/hbv) # hibernate validator @@ -17,7 +17,7 @@ Bean validation via [Hibernate Validator](hibernate.org/validator). org.jooby jooby-hbv - 1.5.0 + 1.6.6 ``` @@ -38,6 +38,19 @@ Bean validation via [Hibernate Validator](hibernate.org/validator). }); } ``` +### in combination with JSON parser +Jooby does not have a validation API or a validation API for HTTP bodies. Instead, this validator _wraps_ existing body parsers as they simply return the first deserialized object. Consequently, this module must be imported _before_ you import any parser! +If you were to use the [Jackson JSON parser module](../jackson/jackson.md) it would look like this: + +```java +{ + // must be imported before any body parser + use(new Hbv()); + use(new Jackson()); + + // routes go here +} +``` ## automatic validations of HTTP params and body diff --git a/modules/jooby-hbv/pom.xml b/modules/jooby-hbv/pom.xml index 768c940598..24a5d90db0 100644 --- a/modules/jooby-hbv/pom.xml +++ b/modules/jooby-hbv/pom.xml @@ -5,7 +5,7 @@ org.jooby modules - 1.5.1-SNAPSHOT + 1.6.9 4.0.0 @@ -49,7 +49,7 @@ - org.glassfish.web + org.glassfish javax.el diff --git a/modules/jooby-jackson/README.md b/modules/jooby-jackson/README.md index d47f09a66a..c153491db4 100644 --- a/modules/jooby-jackson/README.md +++ b/modules/jooby-jackson/README.md @@ -1,5 +1,5 @@ -[![Maven Central](https://maven-badges.herokuapp.com/maven-central/org.jooby/jooby-jackson/badge.svg)](https://maven-badges.herokuapp.com/maven-central/org.jooby/jooby-jackson) -[![javadoc](https://javadoc.io/badge/org.jooby/jooby-jackson.svg)](https://javadoc.io/doc/org.jooby/jooby-jackson/1.5.0) +[![Maven](https://img.shields.io/maven-metadata/v/http/central.maven.org/maven2/org/jooby/jooby-jackson/maven-metadata.xml.svg)](http://mvnrepository.com/artifact/org.jooby/jooby-jackson/1.6.6) +[![javadoc](https://javadoc.io/badge/org.jooby/jooby-jackson.svg)](https://javadoc.io/doc/org.jooby/jooby-jackson/1.6.6) [![jooby-jackson website](https://img.shields.io/badge/jooby-jackson-brightgreen.svg)](http://jooby.org/doc/jackson) # jackson @@ -17,7 +17,7 @@ JSON support from the excellent [Jackson](https://github.com/FasterXML/jackson) org.jooby jooby-jackson - 1.5.0 + 1.6.6 ``` diff --git a/modules/jooby-jackson/pom.xml b/modules/jooby-jackson/pom.xml index 1b92f51530..2f6c37ebf8 100644 --- a/modules/jooby-jackson/pom.xml +++ b/modules/jooby-jackson/pom.xml @@ -5,7 +5,7 @@ org.jooby modules - 1.5.1-SNAPSHOT + 1.6.9 4.0.0 diff --git a/modules/jooby-jackson/src/main/java/org/jooby/json/JacksonRawRenderer.java b/modules/jooby-jackson/src/main/java/org/jooby/json/JacksonRawRenderer.java index fce620ce18..225600c70b 100644 --- a/modules/jooby-jackson/src/main/java/org/jooby/json/JacksonRawRenderer.java +++ b/modules/jooby-jackson/src/main/java/org/jooby/json/JacksonRawRenderer.java @@ -216,7 +216,7 @@ public JacksonRawRenderer(final ObjectMapper mapper, final MediaType type) { @Override protected void renderValue(final Object value, final Renderer.Context ctx) throws Exception { if (value instanceof CharSequence) { - ctx.send(value.toString()); + ctx.type(type).send(value.toString()); } else { super.renderValue(value, ctx); } diff --git a/modules/jooby-jade/README.md b/modules/jooby-jade/README.md index 13a85d89a2..f209cf397d 100644 --- a/modules/jooby-jade/README.md +++ b/modules/jooby-jade/README.md @@ -1,5 +1,5 @@ -[![Maven Central](https://maven-badges.herokuapp.com/maven-central/org.jooby/jooby-jade/badge.svg)](https://maven-badges.herokuapp.com/maven-central/org.jooby/jooby-jade) -[![javadoc](https://javadoc.io/badge/org.jooby/jooby-jade.svg)](https://javadoc.io/doc/org.jooby/jooby-jade/1.5.0) +[![Maven](https://img.shields.io/maven-metadata/v/http/central.maven.org/maven2/org/jooby/jooby-jade/maven-metadata.xml.svg)](http://mvnrepository.com/artifact/org.jooby/jooby-jade/1.6.6) +[![javadoc](https://javadoc.io/badge/org.jooby/jooby-jade.svg)](https://javadoc.io/doc/org.jooby/jooby-jade/1.6.6) [![jooby-jade website](https://img.shields.io/badge/jooby-jade-brightgreen.svg)](http://jooby.org/doc/jade) # jade @@ -16,7 +16,7 @@ org.jooby jooby-jade - 1.5.0 + 1.6.6 ``` diff --git a/modules/jooby-jade/pom.xml b/modules/jooby-jade/pom.xml index 65760cec89..2b5c9ce420 100644 --- a/modules/jooby-jade/pom.xml +++ b/modules/jooby-jade/pom.xml @@ -5,7 +5,7 @@ org.jooby modules - 1.5.1-SNAPSHOT + 1.6.9 4.0.0 diff --git a/modules/jooby-jdbc/README.md b/modules/jooby-jdbc/README.md index 9c918215e3..f06b2e3543 100644 --- a/modules/jooby-jdbc/README.md +++ b/modules/jooby-jdbc/README.md @@ -1,5 +1,5 @@ -[![Maven Central](https://maven-badges.herokuapp.com/maven-central/org.jooby/jooby-jdbc/badge.svg)](https://maven-badges.herokuapp.com/maven-central/org.jooby/jooby-jdbc) -[![javadoc](https://javadoc.io/badge/org.jooby/jooby-jdbc.svg)](https://javadoc.io/doc/org.jooby/jooby-jdbc/1.5.0) +[![Maven](https://img.shields.io/maven-metadata/v/http/central.maven.org/maven2/org/jooby/jooby-jdbc/maven-metadata.xml.svg)](http://mvnrepository.com/artifact/org.jooby/jooby-jdbc/1.6.6) +[![javadoc](https://javadoc.io/badge/org.jooby/jooby-jdbc.svg)](https://javadoc.io/doc/org.jooby/jooby-jdbc/1.6.6) [![jooby-jdbc website](https://img.shields.io/badge/jooby-jdbc-brightgreen.svg)](http://jooby.org/doc/jdbc) # jdbc @@ -15,7 +15,7 @@ Production-ready jdbc data source, powered by the [HikariCP](https://github.com/ org.jooby jooby-jdbc - 1.5.0 + 1.6.6 ``` diff --git a/modules/jooby-jdbc/pom.xml b/modules/jooby-jdbc/pom.xml index 8251bbded0..dbaed2863b 100644 --- a/modules/jooby-jdbc/pom.xml +++ b/modules/jooby-jdbc/pom.xml @@ -6,7 +6,7 @@ org.jooby modules - 1.5.1-SNAPSHOT + 1.6.9 4.0.0 diff --git a/modules/jooby-jdbi/README.md b/modules/jooby-jdbi/README.md index bc30ca5eec..027f3084c7 100644 --- a/modules/jooby-jdbi/README.md +++ b/modules/jooby-jdbi/README.md @@ -1,5 +1,5 @@ -[![Maven Central](https://maven-badges.herokuapp.com/maven-central/org.jooby/jooby-jdbi/badge.svg)](https://maven-badges.herokuapp.com/maven-central/org.jooby/jooby-jdbi) -[![javadoc](https://javadoc.io/badge/org.jooby/jooby-jdbi.svg)](https://javadoc.io/doc/org.jooby/jooby-jdbi/1.5.0) +[![Maven](https://img.shields.io/maven-metadata/v/http/central.maven.org/maven2/org/jooby/jooby-jdbi/maven-metadata.xml.svg)](http://mvnrepository.com/artifact/org.jooby/jooby-jdbi/1.6.6) +[![javadoc](https://javadoc.io/badge/org.jooby/jooby-jdbi.svg)](https://javadoc.io/doc/org.jooby/jooby-jdbi/1.6.6) [![jooby-jdbi website](https://img.shields.io/badge/jooby-jdbi-brightgreen.svg)](http://jooby.org/doc/jdbi) # jdbi @@ -21,7 +21,7 @@ org.jooby jooby-jdbi - 1.5.0 + 1.6.6 ``` diff --git a/modules/jooby-jdbi/pom.xml b/modules/jooby-jdbi/pom.xml index 0dda5dffc8..3f76dd5adf 100644 --- a/modules/jooby-jdbi/pom.xml +++ b/modules/jooby-jdbi/pom.xml @@ -5,7 +5,7 @@ org.jooby modules - 1.5.1-SNAPSHOT + 1.6.9 4.0.0 diff --git a/modules/jooby-jdbi3/README.md b/modules/jooby-jdbi3/README.md index c92dfb0803..e45619dfa4 100644 --- a/modules/jooby-jdbi3/README.md +++ b/modules/jooby-jdbi3/README.md @@ -1,5 +1,5 @@ -[![Maven Central](https://maven-badges.herokuapp.com/maven-central/org.jooby/jooby-jdbi3/badge.svg)](https://maven-badges.herokuapp.com/maven-central/org.jooby/jooby-jdbi3) -[![javadoc](https://javadoc.io/badge/org.jooby/jooby-jdbi3.svg)](https://javadoc.io/doc/org.jooby/jooby-jdbi3/1.5.0) +[![Maven](https://img.shields.io/maven-metadata/v/http/central.maven.org/maven2/org/jooby/jooby-jdbi3/maven-metadata.xml.svg)](http://mvnrepository.com/artifact/org.jooby/jooby-jdbi3/1.6.6) +[![javadoc](https://javadoc.io/badge/org.jooby/jooby-jdbi3.svg)](https://javadoc.io/doc/org.jooby/jooby-jdbi3/1.6.6) [![jooby-jdbi3 website](https://img.shields.io/badge/jooby-jdbi3-brightgreen.svg)](http://jooby.org/doc/jdbi3) # jdbi @@ -17,7 +17,7 @@ org.jooby jooby-jdbi3 - 1.5.0 + 1.6.6 ``` diff --git a/modules/jooby-jdbi3/pom.xml b/modules/jooby-jdbi3/pom.xml index 7b0aadc82d..5be42e0d84 100644 --- a/modules/jooby-jdbi3/pom.xml +++ b/modules/jooby-jdbi3/pom.xml @@ -5,7 +5,7 @@ org.jooby modules - 1.5.1-SNAPSHOT + 1.6.9 4.0.0 diff --git a/modules/jooby-jedis/README.md b/modules/jooby-jedis/README.md index c635f99ac7..0e5a828fc7 100644 --- a/modules/jooby-jedis/README.md +++ b/modules/jooby-jedis/README.md @@ -1,5 +1,5 @@ -[![Maven Central](https://maven-badges.herokuapp.com/maven-central/org.jooby/jooby-jedis/badge.svg)](https://maven-badges.herokuapp.com/maven-central/org.jooby/jooby-jedis) -[![javadoc](https://javadoc.io/badge/org.jooby/jooby-jedis.svg)](https://javadoc.io/doc/org.jooby/jooby-jedis/1.5.0) +[![Maven](https://img.shields.io/maven-metadata/v/http/central.maven.org/maven2/org/jooby/jooby-jedis/maven-metadata.xml.svg)](http://mvnrepository.com/artifact/org.jooby/jooby-jedis/1.6.6) +[![javadoc](https://javadoc.io/badge/org.jooby/jooby-jedis.svg)](https://javadoc.io/doc/org.jooby/jooby-jedis/1.6.6) [![jooby-jedis website](https://img.shields.io/badge/jooby-jedis-brightgreen.svg)](http://jooby.org/doc/jedis) # jedis @@ -11,7 +11,7 @@ org.jooby jooby-jedis - 1.5.0 + 1.6.6 ``` @@ -99,7 +99,7 @@ For more information about [Jedis](https://github.com/xetorthio/jedis) checkout org.jooby jooby-jedis - 1.5.0 + 1.6.6 ``` @@ -202,4 +202,10 @@ jedis.pool.jmxNamePrefix = redis-pool jedis.session.prefix = sessions jedis.session.timeout = ${session.timeout} + +jedis.sentinel.hosts = [] + +jedis.sentinel.master = "master" + +jedis.password = "" ``` diff --git a/modules/jooby-jedis/pom.xml b/modules/jooby-jedis/pom.xml index 49d9fbf7a2..a414963d57 100644 --- a/modules/jooby-jedis/pom.xml +++ b/modules/jooby-jedis/pom.xml @@ -5,7 +5,7 @@ org.jooby modules - 1.5.1-SNAPSHOT + 1.6.9 4.0.0 diff --git a/modules/jooby-jedis/src/main/java/org/jooby/jedis/Redis.java b/modules/jooby-jedis/src/main/java/org/jooby/jedis/Redis.java index 34c4b62308..b8c9e7f69b 100644 --- a/modules/jooby-jedis/src/main/java/org/jooby/jedis/Redis.java +++ b/modules/jooby-jedis/src/main/java/org/jooby/jedis/Redis.java @@ -203,25 +203,22 @@ */ package org.jooby.jedis; -import static java.util.Objects.requireNonNull; - -import java.net.URI; -import java.util.concurrent.TimeUnit; - -import javax.inject.Provider; - +import com.google.inject.Binder; +import com.typesafe.config.Config; +import com.typesafe.config.ConfigFactory; import org.apache.commons.pool2.impl.GenericObjectPoolConfig; import org.jooby.Env; import org.jooby.Env.ServiceKey; import org.jooby.Jooby; - -import com.google.inject.Binder; -import com.typesafe.config.Config; -import com.typesafe.config.ConfigFactory; - import redis.clients.jedis.Jedis; import redis.clients.jedis.JedisPool; +import javax.inject.Provider; +import java.net.URI; +import java.util.concurrent.TimeUnit; + +import static java.util.Objects.requireNonNull; + /** * Redis cache and key/value data store for Jooby. Exposes a {@link Jedis} service. * @@ -378,7 +375,7 @@ public void configure(final Env env, final Config config, final Binder binder) { k -> binder.bind(k).toProvider(jedis)); } - private GenericObjectPoolConfig poolConfig(final Config config, final String name) { + GenericObjectPoolConfig poolConfig(final Config config, final String name) { Config poolConfig = config.getConfig("jedis.pool"); String override = "jedis." + name; if (config.hasPath(override)) { @@ -387,7 +384,7 @@ private GenericObjectPoolConfig poolConfig(final Config config, final String nam return poolConfig(poolConfig); } - private GenericObjectPoolConfig poolConfig(final Config config) { + GenericObjectPoolConfig poolConfig(final Config config) { GenericObjectPoolConfig poolConfig = new GenericObjectPoolConfig(); poolConfig.setBlockWhenExhausted(config.getBoolean("blockWhenExhausted")); poolConfig.setEvictionPolicyClassName(config.getString("evictionPolicyClassName")); diff --git a/modules/jooby-jedis/src/main/java/org/jooby/jedis/RedisProvider.java b/modules/jooby-jedis/src/main/java/org/jooby/jedis/RedisProvider.java index d7e355dc41..1495ca2261 100644 --- a/modules/jooby-jedis/src/main/java/org/jooby/jedis/RedisProvider.java +++ b/modules/jooby-jedis/src/main/java/org/jooby/jedis/RedisProvider.java @@ -203,26 +203,25 @@ */ package org.jooby.jedis; -import java.net.URI; - import org.apache.commons.pool2.impl.GenericObjectPoolConfig; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import redis.clients.util.Pool; -import redis.clients.jedis.JedisPool; +import java.net.URI; class RedisProvider { /** The logging system. */ private final Logger log = LoggerFactory.getLogger(Redis.class); - private JedisPool pool; + private Pool pool; private URI uri; private GenericObjectPoolConfig config; - public RedisProvider(final JedisPool pool, final URI uri, final GenericObjectPoolConfig config) { + public RedisProvider(final Pool pool, final URI uri, final GenericObjectPoolConfig config) { this.pool = pool; this.uri = uri; this.config = config; diff --git a/modules/jooby-jedis/src/main/java/org/jooby/jedis/RedisSentinel.java b/modules/jooby-jedis/src/main/java/org/jooby/jedis/RedisSentinel.java new file mode 100644 index 0000000000..6228daeab7 --- /dev/null +++ b/modules/jooby-jedis/src/main/java/org/jooby/jedis/RedisSentinel.java @@ -0,0 +1,287 @@ +/** + * Apache License + * Version 2.0, January 2004 + * http://www.apache.org/licenses/ + * + * TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + * + * 1. Definitions. + * + * "License" shall mean the terms and conditions for use, reproduction, + * and distribution as defined by Sections 1 through 9 of this document. + * + * "Licensor" shall mean the copyright owner or entity authorized by + * the copyright owner that is granting the License. + * + * "Legal Entity" shall mean the union of the acting entity and all + * other entities that control, are controlled by, or are under common + * control with that entity. For the purposes of this definition, + * "control" means (i) the power, direct or indirect, to cause the + * direction or management of such entity, whether by contract or + * otherwise, or (ii) ownership of fifty percent (50%) or more of the + * outstanding shares, or (iii) beneficial ownership of such entity. + * + * "You" (or "Your") shall mean an individual or Legal Entity + * exercising permissions granted by this License. + * + * "Source" form shall mean the preferred form for making modifications, + * including but not limited to software source code, documentation + * source, and configuration files. + * + * "Object" form shall mean any form resulting from mechanical + * transformation or translation of a Source form, including but + * not limited to compiled object code, generated documentation, + * and conversions to other media types. + * + * "Work" shall mean the work of authorship, whether in Source or + * Object form, made available under the License, as indicated by a + * copyright notice that is included in or attached to the work + * (an example is provided in the Appendix below). + * + * "Derivative Works" shall mean any work, whether in Source or Object + * form, that is based on (or derived from) the Work and for which the + * editorial revisions, annotations, elaborations, or other modifications + * represent, as a whole, an original work of authorship. For the purposes + * of this License, Derivative Works shall not include works that remain + * separable from, or merely link (or bind by name) to the interfaces of, + * the Work and Derivative Works thereof. + * + * "Contribution" shall mean any work of authorship, including + * the original version of the Work and any modifications or additions + * to that Work or Derivative Works thereof, that is intentionally + * submitted to Licensor for inclusion in the Work by the copyright owner + * or by an individual or Legal Entity authorized to submit on behalf of + * the copyright owner. For the purposes of this definition, "submitted" + * means any form of electronic, verbal, or written communication sent + * to the Licensor or its representatives, including but not limited to + * communication on electronic mailing lists, source code control systems, + * and issue tracking systems that are managed by, or on behalf of, the + * Licensor for the purpose of discussing and improving the Work, but + * excluding communication that is conspicuously marked or otherwise + * designated in writing by the copyright owner as "Not a Contribution." + * + * "Contributor" shall mean Licensor and any individual or Legal Entity + * on behalf of whom a Contribution has been received by Licensor and + * subsequently incorporated within the Work. + * + * 2. Grant of Copyright License. Subject to the terms and conditions of + * this License, each Contributor hereby grants to You a perpetual, + * worldwide, non-exclusive, no-charge, royalty-free, irrevocable + * copyright license to reproduce, prepare Derivative Works of, + * publicly display, publicly perform, sublicense, and distribute the + * Work and such Derivative Works in Source or Object form. + * + * 3. Grant of Patent License. Subject to the terms and conditions of + * this License, each Contributor hereby grants to You a perpetual, + * worldwide, non-exclusive, no-charge, royalty-free, irrevocable + * (except as stated in this section) patent license to make, have made, + * use, offer to sell, sell, import, and otherwise transfer the Work, + * where such license applies only to those patent claims licensable + * by such Contributor that are necessarily infringed by their + * Contribution(s) alone or by combination of their Contribution(s) + * with the Work to which such Contribution(s) was submitted. If You + * institute patent litigation against any entity (including a + * cross-claim or counterclaim in a lawsuit) alleging that the Work + * or a Contribution incorporated within the Work constitutes direct + * or contributory patent infringement, then any patent licenses + * granted to You under this License for that Work shall terminate + * as of the date such litigation is filed. + * + * 4. Redistribution. You may reproduce and distribute copies of the + * Work or Derivative Works thereof in any medium, with or without + * modifications, and in Source or Object form, provided that You + * meet the following conditions: + * + * (a) You must give any other recipients of the Work or + * Derivative Works a copy of this License; and + * + * (b) You must cause any modified files to carry prominent notices + * stating that You changed the files; and + * + * (c) You must retain, in the Source form of any Derivative Works + * that You distribute, all copyright, patent, trademark, and + * attribution notices from the Source form of the Work, + * excluding those notices that do not pertain to any part of + * the Derivative Works; and + * + * (d) If the Work includes a "NOTICE" text file as part of its + * distribution, then any Derivative Works that You distribute must + * include a readable copy of the attribution notices contained + * within such NOTICE file, excluding those notices that do not + * pertain to any part of the Derivative Works, in at least one + * of the following places: within a NOTICE text file distributed + * as part of the Derivative Works; within the Source form or + * documentation, if provided along with the Derivative Works; or, + * within a display generated by the Derivative Works, if and + * wherever such third-party notices normally appear. The contents + * of the NOTICE file are for informational purposes only and + * do not modify the License. You may add Your own attribution + * notices within Derivative Works that You distribute, alongside + * or as an addendum to the NOTICE text from the Work, provided + * that such additional attribution notices cannot be construed + * as modifying the License. + * + * You may add Your own copyright statement to Your modifications and + * may provide additional or different license terms and conditions + * for use, reproduction, or distribution of Your modifications, or + * for any such Derivative Works as a whole, provided Your use, + * reproduction, and distribution of the Work otherwise complies with + * the conditions stated in this License. + * + * 5. Submission of Contributions. Unless You explicitly state otherwise, + * any Contribution intentionally submitted for inclusion in the Work + * by You to the Licensor shall be under the terms and conditions of + * this License, without any additional terms or conditions. + * Notwithstanding the above, nothing herein shall supersede or modify + * the terms of any separate license agreement you may have executed + * with Licensor regarding such Contributions. + * + * 6. Trademarks. This License does not grant permission to use the trade + * names, trademarks, service marks, or product names of the Licensor, + * except as required for reasonable and customary use in describing the + * origin of the Work and reproducing the content of the NOTICE file. + * + * 7. Disclaimer of Warranty. Unless required by applicable law or + * agreed to in writing, Licensor provides the Work (and each + * Contributor provides its Contributions) on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied, including, without limitation, any warranties or conditions + * of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + * PARTICULAR PURPOSE. You are solely responsible for determining the + * appropriateness of using or redistributing the Work and assume any + * risks associated with Your exercise of permissions under this License. + * + * 8. Limitation of Liability. In no event and under no legal theory, + * whether in tort (including negligence), contract, or otherwise, + * unless required by applicable law (such as deliberate and grossly + * negligent acts) or agreed to in writing, shall any Contributor be + * liable to You for damages, including any direct, indirect, special, + * incidental, or consequential damages of any character arising as a + * result of this License or out of the use or inability to use the + * Work (including but not limited to damages for loss of goodwill, + * work stoppage, computer failure or malfunction, or any and all + * other commercial damages or losses), even if such Contributor + * has been advised of the possibility of such damages. + * + * 9. Accepting Warranty or Additional Liability. While redistributing + * the Work or Derivative Works thereof, You may choose to offer, + * and charge a fee for, acceptance of support, warranty, indemnity, + * or other liability obligations and/or rights consistent with this + * License. However, in accepting such obligations, You may act only + * on Your own behalf and on Your sole responsibility, not on behalf + * of any other Contributor, and only if You agree to indemnify, + * defend, and hold each Contributor harmless for any liability + * incurred by, or claims asserted against, such Contributor by reason + * of your accepting any such warranty or additional liability. + * + * END OF TERMS AND CONDITIONS + * + * APPENDIX: How to apply the Apache License to your work. + * + * To apply the Apache License to your work, attach the following + * boilerplate notice, with the fields enclosed by brackets "{}" + * replaced with your own identifying information. (Don't include + * the brackets!) The text should be enclosed in the appropriate + * comment syntax for the file format. We also recommend that a + * file or class name and description of purpose be included on the + * same "printed page" as the copyright notice for easier + * identification within third-party archives. + * + * Copyright 2014 Edgar Espina + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jooby.jedis; + +import com.google.inject.Binder; +import com.typesafe.config.Config; +import org.apache.commons.pool2.impl.GenericObjectPoolConfig; +import org.jooby.Env; +import redis.clients.jedis.JedisSentinelPool; + +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.concurrent.TimeUnit; + +/** + * Created by + * + * @author: lis, Luganski Igor + * @since 1.5.0 + */ +public class RedisSentinel extends Redis { + + /** + *

+ * Creates a new {@link RedisSentinel} instance and connect to the provided database. Please note, the + * name is a property in your application.conf file with Redis URI. + * RedisSentinel is pool of Jedis and for get Jedis just call pool.getResource() + *

+ * + *
+     * {
+     *   use(new RedisSentinel("db1"));
+     * }
+     * 
+ * + * application.conf + * + *
+     * jedis.sentinel.hosts = ["localhost:26379", "host2:26379"]
+     * jedis.sentinel.master = "master"
+     * jedis.password = "mySuperSecretPasswordPutHere"
+     * 
+ * + * Example: + *
+     * try (Jedis redis = request.require(JedisSentinelPool.class).getResource()) {
+     *   System.out.println( redis.set("test", "this is work") );
+     *   System.out.println( redis.get("test");
+     * } catch (Exception e) {
+     *   e.printStackTrace();
+     * }
+     * 
+ */ + + @Override + public void configure(Env env, Config config, Binder binder) { + /** + * Pool + */ + GenericObjectPoolConfig poolConfig = poolConfig(config.getConfig("jedis.pool")); + int timeout = (int) config.getDuration("jedis.timeout", TimeUnit.MILLISECONDS); + + List hosts = config.getStringList("jedis.sentinel.hosts"); + if (hosts.size() < 1) throw new IllegalArgumentException("List of hosts (jedis.sentinel.hosts) can not be empty"); + final Set sentinels = new HashSet<>(hosts); + + final String MASTER_NAME = config.getString("jedis.sentinel.master"); + final String REDIS_PASSWORD = config.getString("jedis.password"); + + JedisSentinelPool pool; + if (REDIS_PASSWORD.length() > 0) { + pool = new JedisSentinelPool(MASTER_NAME, sentinels, poolConfig, timeout, REDIS_PASSWORD); + } else { + pool = new JedisSentinelPool(MASTER_NAME, sentinels, poolConfig, timeout); + } + + RedisProvider provider = new RedisProvider(pool, null, poolConfig); + env.onStart(provider::start); + env.onStop(provider::stop); + + Env.ServiceKey serviceKey = env.serviceKey(); + serviceKey.generate(JedisSentinelPool.class, "db", k -> binder.bind(k).toInstance(pool)); + } + +} diff --git a/modules/jooby-jedis/src/main/resources/org/jooby/jedis/jedis.conf b/modules/jooby-jedis/src/main/resources/org/jooby/jedis/jedis.conf index 08f9265f15..1fd32239da 100644 --- a/modules/jooby-jedis/src/main/resources/org/jooby/jedis/jedis.conf +++ b/modules/jooby-jedis/src/main/resources/org/jooby/jedis/jedis.conf @@ -24,3 +24,7 @@ jedis.pool.jmxNamePrefix = redis-pool # session store, key prefix and timeout in seconds jedis.session.prefix = sessions jedis.session.timeout = ${session.timeout} + +jedis.sentinel.hosts = [] +jedis.sentinel.master = "master" +jedis.password = "" \ No newline at end of file diff --git a/modules/jooby-jedis/src/test/java/org/jooby/jedis/RedisSentinelTest.java b/modules/jooby-jedis/src/test/java/org/jooby/jedis/RedisSentinelTest.java new file mode 100644 index 0000000000..51b638fa06 --- /dev/null +++ b/modules/jooby-jedis/src/test/java/org/jooby/jedis/RedisSentinelTest.java @@ -0,0 +1,96 @@ +package org.jooby.jedis; + +import com.google.inject.Binder; +import com.google.inject.Key; +import com.google.inject.binder.AnnotatedBindingBuilder; +import com.google.inject.name.Names; +import com.typesafe.config.Config; +import com.typesafe.config.ConfigFactory; +import com.typesafe.config.ConfigValueFactory; +import org.apache.commons.pool2.impl.GenericObjectPoolConfig; +import org.jooby.Env; +import org.jooby.funzy.Throwing; +import org.jooby.test.MockUnit; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; +import redis.clients.jedis.JedisSentinelPool; + +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; + +import static org.easymock.EasyMock.expect; +import static org.easymock.EasyMock.isA; +import static org.junit.Assert.assertNotNull; + + +@RunWith(PowerMockRunner.class) +@PrepareForTest({RedisSentinel.class, JedisSentinelPool.class, GenericObjectPoolConfig.class}) +public class RedisSentinelTest { + + private MockUnit.Block onManaged = unit -> { + Env env = unit.get(Env.class); + expect(env.onStart(isA(Throwing.Runnable.class))).andReturn(env); + expect(env.onStop(isA(Throwing.Runnable.class))).andReturn(env); + }; + + @SuppressWarnings("unchecked") + @Test + public void shouldGetJedisSentinelInstance() throws Exception { + Config config = jedisConfig().withValue("db", ConfigValueFactory.fromAnyRef("redis://localhost:26379")) + .withValue("jedis.sentinel.hosts", ConfigValueFactory.fromAnyRef(Collections.singletonList("localhost:26379"))); + new MockUnit(Env.class, Binder.class, JedisSentinelPool.class) + .expect(unit -> { + Env env = unit.get(Env.class); + expect(env.serviceKey()).andReturn(new Env.ServiceKey()); + }) + .expect(unit -> { + GenericObjectPoolConfig poolConf = unit.mockConstructor(GenericObjectPoolConfig.class); + poolConf.setBlockWhenExhausted(true); + poolConf.setEvictionPolicyClassName("org.apache.commons.pool2.impl.DefaultEvictionPolicy"); + poolConf.setJmxEnabled(false); + poolConf.setJmxNamePrefix("redis-pool"); + poolConf.setLifo(true); + poolConf.setMaxIdle(10); + poolConf.setMaxTotal(128); + poolConf.setMaxWaitMillis(-1); + poolConf.setMinEvictableIdleTimeMillis(1800000L); + poolConf.setMinIdle(10); + poolConf.setNumTestsPerEvictionRun(3); + poolConf.setSoftMinEvictableIdleTimeMillis(1800000L); + poolConf.setTestOnBorrow(false); + poolConf.setTestOnReturn(false); + poolConf.setTestWhileIdle(false); + poolConf.setTimeBetweenEvictionRunsMillis(-1); + + HashSet hosts = new HashSet<>(); + hosts.add("localhost:26379"); + + JedisSentinelPool pool = unit.mockConstructor( + JedisSentinelPool.class, + new Class[]{String.class, Set.class, GenericObjectPoolConfig.class, int.class}, + "master", hosts, poolConf, 2000); + + AnnotatedBindingBuilder jpABB = unit.mock(AnnotatedBindingBuilder.class); + jpABB.toInstance(pool); + jpABB.toInstance(pool); + + Binder binder = unit.get(Binder.class); + expect(binder.bind(Key.get(JedisSentinelPool.class))).andReturn(jpABB); + expect(binder.bind(Key.get(JedisSentinelPool.class, Names.named("db")))).andReturn(jpABB); + }) + .expect(onManaged) + .run(unit -> { + new RedisSentinel().configure(unit.get(Env.class), config, unit.get(Binder.class)); + }, unit -> { + assertNotNull(unit.get(JedisSentinelPool.class)); + }); + } + + private Config jedisConfig() { + return ConfigFactory.parseResources(getClass(), "jedis.conf"); + } + +} diff --git a/modules/jooby-jetty/README.md b/modules/jooby-jetty/README.md index 6bb722e559..d522fb745c 100644 --- a/modules/jooby-jetty/README.md +++ b/modules/jooby-jetty/README.md @@ -1,5 +1,5 @@ -[![Maven Central](https://maven-badges.herokuapp.com/maven-central/org.jooby/jooby-jetty/badge.svg)](https://maven-badges.herokuapp.com/maven-central/org.jooby/jooby-jetty) -[![javadoc](https://javadoc.io/badge/org.jooby/jooby-jetty.svg)](https://javadoc.io/doc/org.jooby/jooby-jetty/1.5.0) +[![Maven](https://img.shields.io/maven-metadata/v/http/central.maven.org/maven2/org/jooby/jooby-jetty/maven-metadata.xml.svg)](http://mvnrepository.com/artifact/org.jooby/jooby-jetty/1.6.6) +[![javadoc](https://javadoc.io/badge/org.jooby/jooby-jetty.svg)](https://javadoc.io/doc/org.jooby/jooby-jetty/1.6.6) [![jooby-jetty website](https://img.shields.io/badge/jooby-jetty-brightgreen.svg)](http://jooby.org/doc/jetty) # jetty @@ -15,7 +15,7 @@ org.jooby jooby-jetty - 1.5.0 + 1.6.6 ``` @@ -84,10 +84,6 @@ jetty { AcceptQueueSize = 0 - # Use -1 to disable - - SoLingerTime = -1 - StopTimeout = 30000 # Sets the maximum Idle time for a connection, which roughly translates to the Socket#setSoTimeout(int) diff --git a/modules/jooby-jetty/pom.xml b/modules/jooby-jetty/pom.xml index 6291413a77..8440189181 100644 --- a/modules/jooby-jetty/pom.xml +++ b/modules/jooby-jetty/pom.xml @@ -5,7 +5,7 @@ org.jooby modules - 1.5.1-SNAPSHOT + 1.6.9 4.0.0 diff --git a/modules/jooby-jetty/src/main/java/org/jooby/internal/jetty/JettyHandler.java b/modules/jooby-jetty/src/main/java/org/jooby/internal/jetty/JettyHandler.java index 738ad06039..b7a3478d5b 100644 --- a/modules/jooby-jetty/src/main/java/org/jooby/internal/jetty/JettyHandler.java +++ b/modules/jooby-jetty/src/main/java/org/jooby/internal/jetty/JettyHandler.java @@ -258,7 +258,7 @@ public void handle(final String target, final Request baseRequest, String type = baseRequest.getContentType(); boolean multipart = false; if (type != null && type.toLowerCase().startsWith(MediaType.multipart.name())) { - baseRequest.setAttribute(Request.__MULTIPART_CONFIG_ELEMENT, multiPartConfig); + baseRequest.setAttribute(Request.MULTIPART_CONFIG_ELEMENT, multiPartConfig); multipart = true; } diff --git a/modules/jooby-jetty/src/main/java/org/jooby/internal/jetty/JettyServer.java b/modules/jooby-jetty/src/main/java/org/jooby/internal/jetty/JettyServer.java index dd59064952..03f6ae12d6 100644 --- a/modules/jooby-jetty/src/main/java/org/jooby/internal/jetty/JettyServer.java +++ b/modules/jooby-jetty/src/main/java/org/jooby/internal/jetty/JettyServer.java @@ -341,6 +341,7 @@ private ServerConnector https(final Server server, final Config conf, final Stri sslContextFactory.setSslContext(sslContext); sslContextFactory.setIncludeProtocols("TLSv1.2"); sslContextFactory.setIncludeCipherSuites("TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256"); + sslContextFactory.setEndpointIdentificationAlgorithm("HTTPS"); HttpConfiguration httpsConf = new HttpConfiguration(httpConf); httpsConf.addCustomizer(new SecureRequestCustomizer()); diff --git a/modules/jooby-jetty/src/main/resources/org/jooby/spi/server.conf b/modules/jooby-jetty/src/main/resources/org/jooby/spi/server.conf index f45a7962f9..d3d6968eab 100644 --- a/modules/jooby-jetty/src/main/resources/org/jooby/spi/server.conf +++ b/modules/jooby-jetty/src/main/resources/org/jooby/spi/server.conf @@ -36,9 +36,6 @@ jetty { # The accept queue size (also known as accept backlog) AcceptQueueSize = 0 - # Use -1 to disable - SoLingerTime = -1 - StopTimeout = 30000 # Sets the maximum Idle time for a connection, which roughly translates to the Socket#setSoTimeout(int) diff --git a/modules/jooby-jetty/src/test/java/org/jooby/internal/jetty/JettyHandlerTest.java b/modules/jooby-jetty/src/test/java/org/jooby/internal/jetty/JettyHandlerTest.java index 7310c19486..ed94d516db 100644 --- a/modules/jooby-jetty/src/test/java/org/jooby/internal/jetty/JettyHandlerTest.java +++ b/modules/jooby-jetty/src/test/java/org/jooby/internal/jetty/JettyHandlerTest.java @@ -39,7 +39,7 @@ public void handleShouldSetMultipartConfig() throws Exception { expect(request.getContentType()).andReturn("Multipart/Form-Data"); - request.setAttribute(eq(Request.__MULTIPART_CONFIG_ELEMENT), + request.setAttribute(eq(Request.MULTIPART_CONFIG_ELEMENT), isA(MultipartConfigElement.class)); }) .expect(unit -> { diff --git a/modules/jooby-jongo/README.md b/modules/jooby-jongo/README.md index 8ff992f93e..2c45a0891b 100644 --- a/modules/jooby-jongo/README.md +++ b/modules/jooby-jongo/README.md @@ -1,5 +1,5 @@ -[![Maven Central](https://maven-badges.herokuapp.com/maven-central/org.jooby/jooby-jongo/badge.svg)](https://maven-badges.herokuapp.com/maven-central/org.jooby/jooby-jongo) -[![javadoc](https://javadoc.io/badge/org.jooby/jooby-jongo.svg)](https://javadoc.io/doc/org.jooby/jooby-jongo/1.5.0) +[![Maven](https://img.shields.io/maven-metadata/v/http/central.maven.org/maven2/org/jooby/jooby-jongo/maven-metadata.xml.svg)](http://mvnrepository.com/artifact/org.jooby/jooby-jongo/1.6.6) +[![javadoc](https://javadoc.io/badge/org.jooby/jooby-jongo.svg)](https://javadoc.io/doc/org.jooby/jooby-jongo/1.6.6) [![jooby-jongo website](https://img.shields.io/badge/jooby-jongo-brightgreen.svg)](http://jooby.org/doc/jongo) # jongo @@ -17,7 +17,7 @@ org.jooby jooby-jongo - 1.5.0 + 1.6.6 ``` diff --git a/modules/jooby-jongo/pom.xml b/modules/jooby-jongo/pom.xml index 2ae0ebbf25..26eeb8a4f8 100644 --- a/modules/jooby-jongo/pom.xml +++ b/modules/jooby-jongo/pom.xml @@ -5,7 +5,7 @@ org.jooby modules - 1.5.1-SNAPSHOT + 1.6.9 4.0.0 diff --git a/modules/jooby-jooq/README.md b/modules/jooby-jooq/README.md index 362cb01670..a9219410cf 100644 --- a/modules/jooby-jooq/README.md +++ b/modules/jooby-jooq/README.md @@ -1,5 +1,5 @@ -[![Maven Central](https://maven-badges.herokuapp.com/maven-central/org.jooby/jooby-jooq/badge.svg)](https://maven-badges.herokuapp.com/maven-central/org.jooby/jooby-jooq) -[![javadoc](https://javadoc.io/badge/org.jooby/jooby-jooq.svg)](https://javadoc.io/doc/org.jooby/jooby-jooq/1.5.0) +[![Maven](https://img.shields.io/maven-metadata/v/http/central.maven.org/maven2/org/jooby/jooby-jooq/maven-metadata.xml.svg)](http://mvnrepository.com/artifact/org.jooby/jooby-jooq/1.6.6) +[![javadoc](https://javadoc.io/badge/org.jooby/jooby-jooq.svg)](https://javadoc.io/doc/org.jooby/jooby-jooq/1.6.6) [![jooby-jooq website](https://img.shields.io/badge/jooby-jooq-brightgreen.svg)](http://jooby.org/doc/jooq) # jOOQ @@ -17,7 +17,7 @@ org.jooby jooby-jooq - 1.5.0 + 1.6.6 ``` diff --git a/modules/jooby-jooq/pom.xml b/modules/jooby-jooq/pom.xml index f61045f3f5..b4b14b37f6 100644 --- a/modules/jooby-jooq/pom.xml +++ b/modules/jooby-jooq/pom.xml @@ -5,7 +5,7 @@ org.jooby modules - 1.5.1-SNAPSHOT + 1.6.9 4.0.0 diff --git a/modules/jooby-lang-kotlin/README.md b/modules/jooby-lang-kotlin/README.md index 12062f18fc..c1cbc68ae8 100644 --- a/modules/jooby-lang-kotlin/README.md +++ b/modules/jooby-lang-kotlin/README.md @@ -1,5 +1,5 @@ -[![Maven Central](https://maven-badges.herokuapp.com/maven-central/org.jooby/jooby-lang-kotlin/badge.svg)](https://maven-badges.herokuapp.com/maven-central/org.jooby/jooby-lang-kotlin) -[![javadoc](https://javadoc.io/badge/org.jooby/jooby-lang-kotlin.svg)](https://javadoc.io/doc/org.jooby/jooby-lang-kotlin/1.5.0) +[![Maven](https://img.shields.io/maven-metadata/v/http/central.maven.org/maven2/org/jooby/jooby-lang-kotlin/maven-metadata.xml.svg)](http://mvnrepository.com/artifact/org.jooby/jooby-lang-kotlin/1.6.6) +[![javadoc](https://javadoc.io/badge/org.jooby/jooby-lang-kotlin.svg)](https://javadoc.io/doc/org.jooby/jooby-lang-kotlin/1.6.6) [![jooby-lang-kotlin website](https://img.shields.io/badge/jooby-lang-kotlin-brightgreen.svg)](http://jooby.org/doc/lang-kotlin) # kotlin @@ -11,7 +11,7 @@ A tiny module that makes a Jooby application more Kotlin idiomatic. org.jooby jooby-lang-kotlin - 1.5.0 + 1.6.6 ``` diff --git a/modules/jooby-lang-kotlin/pom.xml b/modules/jooby-lang-kotlin/pom.xml index 79960f54f2..5d8c6561e2 100644 --- a/modules/jooby-lang-kotlin/pom.xml +++ b/modules/jooby-lang-kotlin/pom.xml @@ -5,7 +5,7 @@ org.jooby modules - 1.5.1-SNAPSHOT + 1.6.9 4.0.0 diff --git a/modules/jooby-livereload/README.md b/modules/jooby-livereload/README.md index 4827ab6688..30de9a580b 100644 --- a/modules/jooby-livereload/README.md +++ b/modules/jooby-livereload/README.md @@ -1,5 +1,5 @@ -[![Maven Central](https://maven-badges.herokuapp.com/maven-central/org.jooby/jooby-livereload/badge.svg)](https://maven-badges.herokuapp.com/maven-central/org.jooby/jooby-livereload) -[![javadoc](https://javadoc.io/badge/org.jooby/jooby-livereload.svg)](https://javadoc.io/doc/org.jooby/jooby-livereload/1.5.0) +[![Maven](https://img.shields.io/maven-metadata/v/http/central.maven.org/maven2/org/jooby/jooby-livereload/maven-metadata.xml.svg)](http://mvnrepository.com/artifact/org.jooby/jooby-livereload/1.6.6) +[![javadoc](https://javadoc.io/badge/org.jooby/jooby-livereload.svg)](https://javadoc.io/doc/org.jooby/jooby-livereload/1.6.6) [![jooby-livereload website](https://img.shields.io/badge/jooby-livereload-brightgreen.svg)](http://jooby.org/doc/livereload) # liveReload @@ -18,7 +18,7 @@ Even cooler, when you change a CSS file or an image, the browser is updated inst org.jooby jooby-livereload - 1.5.0 + 1.6.6 ``` diff --git a/modules/jooby-livereload/pom.xml b/modules/jooby-livereload/pom.xml index 3b9019aa54..9b0b302010 100644 --- a/modules/jooby-livereload/pom.xml +++ b/modules/jooby-livereload/pom.xml @@ -6,7 +6,7 @@ org.jooby modules - 1.5.1-SNAPSHOT + 1.6.9 jooby-livereload jooby-livereload diff --git a/modules/jooby-maven-plugin/README.md b/modules/jooby-maven-plugin/README.md index 29eca49944..85c19f609a 100644 --- a/modules/jooby-maven-plugin/README.md +++ b/modules/jooby-maven-plugin/README.md @@ -1,5 +1,5 @@ -[![Maven Central](https://maven-badges.herokuapp.com/maven-central/org.jooby/jooby-maven-plugin/badge.svg)](https://maven-badges.herokuapp.com/maven-central/org.jooby/jooby-maven-plugin) -[![javadoc](https://javadoc.io/badge/org.jooby/jooby-maven-plugin.svg)](https://javadoc.io/doc/org.jooby/jooby-maven-plugin/1.5.0) +[![Maven](https://img.shields.io/maven-metadata/v/http/central.maven.org/maven2/org/jooby/jooby-maven-plugin/maven-metadata.xml.svg)](http://mvnrepository.com/artifact/org.jooby/jooby-maven-plugin/1.6.6) +[![javadoc](https://javadoc.io/badge/org.jooby/jooby-maven-plugin.svg)](https://javadoc.io/doc/org.jooby/jooby-maven-plugin/1.6.6) [![jooby-maven-plugin website](https://img.shields.io/badge/jooby-maven-plugin-brightgreen.svg)](http://jooby.org/doc/maven-plugin) # maven @@ -43,7 +43,7 @@ It's worth to mention that dynamic reload of classes is done via [JBoss Modules] org.jooby jooby-maven-plugin - 1.5.0 + 1.6.6 ${application.class} @@ -117,7 +117,7 @@ List of commands to execute before starting the ```application```. Useful for [n org.jooby jooby-maven-plugin - 1.5.0 + 1.6.6 ${application.class} @@ -138,7 +138,7 @@ Set one or more ```JVM args```: org.jooby jooby-maven-plugin - 1.5.0 + 1.6.6 ${application.class} true diff --git a/modules/jooby-maven-plugin/pom.xml b/modules/jooby-maven-plugin/pom.xml index 7e4dcf8336..1760e2b4b6 100644 --- a/modules/jooby-maven-plugin/pom.xml +++ b/modules/jooby-maven-plugin/pom.xml @@ -6,7 +6,7 @@ org.jooby modules - 1.5.1-SNAPSHOT + 1.6.9 4.0.0 diff --git a/modules/jooby-metrics/README.md b/modules/jooby-metrics/README.md index c9aede6d79..292f9cce80 100644 --- a/modules/jooby-metrics/README.md +++ b/modules/jooby-metrics/README.md @@ -1,5 +1,5 @@ -[![Maven Central](https://maven-badges.herokuapp.com/maven-central/org.jooby/jooby-metrics/badge.svg)](https://maven-badges.herokuapp.com/maven-central/org.jooby/jooby-metrics) -[![javadoc](https://javadoc.io/badge/org.jooby/jooby-metrics.svg)](https://javadoc.io/doc/org.jooby/jooby-metrics/1.5.0) +[![Maven](https://img.shields.io/maven-metadata/v/http/central.maven.org/maven2/org/jooby/jooby-metrics/maven-metadata.xml.svg)](http://mvnrepository.com/artifact/org.jooby/jooby-metrics/1.6.6) +[![javadoc](https://javadoc.io/badge/org.jooby/jooby-metrics.svg)](https://javadoc.io/doc/org.jooby/jooby-metrics/1.6.6) [![jooby-metrics website](https://img.shields.io/badge/jooby-metrics-brightgreen.svg)](http://jooby.org/doc/metrics) # metrics @@ -11,7 +11,7 @@ org.jooby jooby-metrics - 1.5.0 + 1.6.6 ``` diff --git a/modules/jooby-metrics/pom.xml b/modules/jooby-metrics/pom.xml index 7c7dc0e712..b748fba8f8 100644 --- a/modules/jooby-metrics/pom.xml +++ b/modules/jooby-metrics/pom.xml @@ -5,7 +5,7 @@ org.jooby modules - 1.5.1-SNAPSHOT + 1.6.9 4.0.0 diff --git a/modules/jooby-micrometer/README.md b/modules/jooby-micrometer/README.md index a397804867..e92ad2d180 100644 --- a/modules/jooby-micrometer/README.md +++ b/modules/jooby-micrometer/README.md @@ -1,5 +1,5 @@ -[![Maven Central](https://maven-badges.herokuapp.com/maven-central/org.jooby/jooby-micrometer/badge.svg)](https://maven-badges.herokuapp.com/maven-central/org.jooby/jooby-micrometer) -[![javadoc](https://javadoc.io/badge/org.jooby/jooby-micrometer.svg)](https://javadoc.io/doc/org.jooby/jooby-micrometer/1.5.0) +[![Maven](https://img.shields.io/maven-metadata/v/http/central.maven.org/maven2/org/jooby/jooby-micrometer/maven-metadata.xml.svg)](http://mvnrepository.com/artifact/org.jooby/jooby-micrometer/1.6.6) +[![javadoc](https://javadoc.io/badge/org.jooby/jooby-micrometer.svg)](https://javadoc.io/doc/org.jooby/jooby-micrometer/1.6.6) [![jooby-micrometer website](https://img.shields.io/badge/jooby-micrometer-brightgreen.svg)](http://jooby.org/doc/micrometer) # micrometer @@ -11,7 +11,7 @@ org.jooby jooby-micrometer - 1.5.0 + 1.6.6 ``` @@ -81,6 +81,15 @@ import org.jooby.micrometer.PrometheusHandler; } ``` +> NOTE: for each additional registry, you must add the corresponding `micrometer` depedency. For
Prometheus: + +```xml + + io.micrometer + micrometer-registry-prometheus + +``` + ## timed annotation Jooby supports the ```io.micrometer.core.annotation.Timed``` annotation for MVC routes: diff --git a/modules/jooby-micrometer/pom.xml b/modules/jooby-micrometer/pom.xml index 240aa47590..cbf0151a87 100644 --- a/modules/jooby-micrometer/pom.xml +++ b/modules/jooby-micrometer/pom.xml @@ -5,7 +5,7 @@ org.jooby modules - 1.5.1-SNAPSHOT + 1.6.9 4.0.0 diff --git a/modules/jooby-mongodb-rx/README.md b/modules/jooby-mongodb-rx/README.md index 47aa948b45..8bc159c481 100644 --- a/modules/jooby-mongodb-rx/README.md +++ b/modules/jooby-mongodb-rx/README.md @@ -1,5 +1,5 @@ -[![Maven Central](https://maven-badges.herokuapp.com/maven-central/org.jooby/jooby-mongodb-rx/badge.svg)](https://maven-badges.herokuapp.com/maven-central/org.jooby/jooby-mongodb-rx) -[![javadoc](https://javadoc.io/badge/org.jooby/jooby-mongodb-rx.svg)](https://javadoc.io/doc/org.jooby/jooby-mongodb-rx/1.5.0) +[![Maven](https://img.shields.io/maven-metadata/v/http/central.maven.org/maven2/org/jooby/jooby-mongodb-rx/maven-metadata.xml.svg)](http://mvnrepository.com/artifact/org.jooby/jooby-mongodb-rx/1.6.6) +[![javadoc](https://javadoc.io/badge/org.jooby/jooby-mongodb-rx.svg)](https://javadoc.io/doc/org.jooby/jooby-mongodb-rx/1.6.6) [![jooby-mongodb-rx website](https://img.shields.io/badge/jooby-mongodb-rx-brightgreen.svg)](http://jooby.org/doc/mongodb-rx) # mongodb-rx @@ -16,7 +16,7 @@ A MongoDB based driver providing support for React org.jooby jooby-mongodb-rx - 1.5.0 + 1.6.6 ``` diff --git a/modules/jooby-mongodb-rx/pom.xml b/modules/jooby-mongodb-rx/pom.xml index 0e0096b4cb..35dfb8c62e 100644 --- a/modules/jooby-mongodb-rx/pom.xml +++ b/modules/jooby-mongodb-rx/pom.xml @@ -5,7 +5,7 @@ org.jooby modules - 1.5.1-SNAPSHOT + 1.6.9 4.0.0 diff --git a/modules/jooby-mongodb/README.md b/modules/jooby-mongodb/README.md index 6da253ef4f..8f728ca4f8 100644 --- a/modules/jooby-mongodb/README.md +++ b/modules/jooby-mongodb/README.md @@ -1,5 +1,5 @@ -[![Maven Central](https://maven-badges.herokuapp.com/maven-central/org.jooby/jooby-mongodb/badge.svg)](https://maven-badges.herokuapp.com/maven-central/org.jooby/jooby-mongodb) -[![javadoc](https://javadoc.io/badge/org.jooby/jooby-mongodb.svg)](https://javadoc.io/doc/org.jooby/jooby-mongodb/1.5.0) +[![Maven](https://img.shields.io/maven-metadata/v/http/central.maven.org/maven2/org/jooby/jooby-mongodb/maven-metadata.xml.svg)](http://mvnrepository.com/artifact/org.jooby/jooby-mongodb/1.6.6) +[![javadoc](https://javadoc.io/badge/org.jooby/jooby-mongodb.svg)](https://javadoc.io/doc/org.jooby/jooby-mongodb/1.6.6) [![jooby-mongodb website](https://img.shields.io/badge/jooby-mongodb-brightgreen.svg)](http://jooby.org/doc/mongodb) # mongodb driver @@ -17,7 +17,7 @@ org.jooby jooby-mongodb - 1.5.0 + 1.6.6 ``` @@ -117,7 +117,7 @@ Use [named](/apidocs/org/jooby/mongodb/Mongodb.html#-named) when you need two or org.jooby jooby-mongodb - 1.5.0 + 1.6.6 ``` diff --git a/modules/jooby-mongodb/pom.xml b/modules/jooby-mongodb/pom.xml index 94a9b50e6a..bebe22ff7d 100644 --- a/modules/jooby-mongodb/pom.xml +++ b/modules/jooby-mongodb/pom.xml @@ -5,7 +5,7 @@ org.jooby modules - 1.5.1-SNAPSHOT + 1.6.9 4.0.0 diff --git a/modules/jooby-morphia/README.md b/modules/jooby-morphia/README.md index 08854e6180..9849397a14 100644 --- a/modules/jooby-morphia/README.md +++ b/modules/jooby-morphia/README.md @@ -1,5 +1,5 @@ -[![Maven Central](https://maven-badges.herokuapp.com/maven-central/org.jooby/jooby-morphia/badge.svg)](https://maven-badges.herokuapp.com/maven-central/org.jooby/jooby-morphia) -[![javadoc](https://javadoc.io/badge/org.jooby/jooby-morphia.svg)](https://javadoc.io/doc/org.jooby/jooby-morphia/1.5.0) +[![Maven](https://img.shields.io/maven-metadata/v/http/central.maven.org/maven2/org/jooby/jooby-morphia/maven-metadata.xml.svg)](http://mvnrepository.com/artifact/org.jooby/jooby-morphia/1.6.6) +[![javadoc](https://javadoc.io/badge/org.jooby/jooby-morphia.svg)](https://javadoc.io/doc/org.jooby/jooby-morphia/1.6.6) [![jooby-morphia website](https://img.shields.io/badge/jooby-morphia-brightgreen.svg)](http://jooby.org/doc/morphia) # morphia @@ -16,7 +16,7 @@ Extends the [mongodb](https://github.com/jooby-project/jooby/tree/master/jooby-m org.jooby jooby-morphia - 1.5.0 + 1.6.6 ``` diff --git a/modules/jooby-morphia/pom.xml b/modules/jooby-morphia/pom.xml index 1e0a1543ae..4524829786 100644 --- a/modules/jooby-morphia/pom.xml +++ b/modules/jooby-morphia/pom.xml @@ -5,7 +5,7 @@ org.jooby modules - 1.5.1-SNAPSHOT + 1.6.9 4.0.0 diff --git a/modules/jooby-neo4j/README.md b/modules/jooby-neo4j/README.md index 6886784ae5..c4d01ee49d 100644 --- a/modules/jooby-neo4j/README.md +++ b/modules/jooby-neo4j/README.md @@ -1,5 +1,5 @@ -[![Maven Central](https://maven-badges.herokuapp.com/maven-central/org.jooby/jooby-neo4j/badge.svg)](https://maven-badges.herokuapp.com/maven-central/org.jooby/jooby-neo4j) -[![javadoc](https://javadoc.io/badge/org.jooby/jooby-neo4j.svg)](https://javadoc.io/doc/org.jooby/jooby-neo4j/1.5.0) +[![Maven](https://img.shields.io/maven-metadata/v/http/central.maven.org/maven2/org/jooby/jooby-neo4j/maven-metadata.xml.svg)](http://mvnrepository.com/artifact/org.jooby/jooby-neo4j/1.6.6) +[![javadoc](https://javadoc.io/badge/org.jooby/jooby-neo4j.svg)](https://javadoc.io/doc/org.jooby/jooby-neo4j/1.6.6) [![jooby-neo4j website](https://img.shields.io/badge/jooby-neo4j-brightgreen.svg)](http://jooby.org/doc/neo4j) # neo4j @@ -13,7 +13,7 @@ This module give you access to neo4j and org.jooby jooby-neo4j - 1.5.0 + 1.6.6 ``` @@ -176,7 +176,7 @@ A [Session.Store](/apidocs/org/jooby/neo4j/Neo4jSessionStore) powered by org.jooby jooby-neo4j - 1.5.0 + 1.6.6 ``` diff --git a/modules/jooby-neo4j/pom.xml b/modules/jooby-neo4j/pom.xml index 0fabdd2046..5344a7b496 100644 --- a/modules/jooby-neo4j/pom.xml +++ b/modules/jooby-neo4j/pom.xml @@ -5,7 +5,7 @@ org.jooby modules - 1.5.1-SNAPSHOT + 1.6.9 4.0.0 diff --git a/modules/jooby-netty/README.md b/modules/jooby-netty/README.md index 780c999fbe..6ae7eec12b 100644 --- a/modules/jooby-netty/README.md +++ b/modules/jooby-netty/README.md @@ -1,5 +1,5 @@ -[![Maven Central](https://maven-badges.herokuapp.com/maven-central/org.jooby/jooby-netty/badge.svg)](https://maven-badges.herokuapp.com/maven-central/org.jooby/jooby-netty) -[![javadoc](https://javadoc.io/badge/org.jooby/jooby-netty.svg)](https://javadoc.io/doc/org.jooby/jooby-netty/1.5.0) +[![Maven](https://img.shields.io/maven-metadata/v/http/central.maven.org/maven2/org/jooby/jooby-netty/maven-metadata.xml.svg)](http://mvnrepository.com/artifact/org.jooby/jooby-netty/1.6.6) +[![javadoc](https://javadoc.io/badge/org.jooby/jooby-netty.svg)](https://javadoc.io/doc/org.jooby/jooby-netty/1.6.6) [![jooby-netty website](https://img.shields.io/badge/jooby-netty-brightgreen.svg)](http://jooby.org/doc/netty) # netty @@ -15,7 +15,7 @@ org.jooby jooby-netty - 1.5.0 + 1.6.6 ``` diff --git a/modules/jooby-netty/pom.xml b/modules/jooby-netty/pom.xml index 49e7596814..50c3d0d488 100644 --- a/modules/jooby-netty/pom.xml +++ b/modules/jooby-netty/pom.xml @@ -5,7 +5,7 @@ org.jooby modules - 1.5.1-SNAPSHOT + 1.6.9 4.0.0 diff --git a/modules/jooby-netty/src/main/java/org/jooby/internal/netty/NettyPush.java b/modules/jooby-netty/src/main/java/org/jooby/internal/netty/NettyPush.java index cf331ed7df..157f184a23 100644 --- a/modules/jooby-netty/src/main/java/org/jooby/internal/netty/NettyPush.java +++ b/modules/jooby-netty/src/main/java/org/jooby/internal/netty/NettyPush.java @@ -261,7 +261,7 @@ public void push(final String method, final String path, final Map files(final String name) throws IOException { return ImmutableList.copyOf(this.files.get(name)); } + @Override + public List files() throws IOException { + decodeParams(); + return ImmutableList.copyOf(this.files.values()); + } + @Override public InputStream in() { ByteBuf content = ((HttpContent) req).content(); diff --git a/modules/jooby-netty/src/main/java/org/jooby/internal/netty/NettyWebSocket.java b/modules/jooby-netty/src/main/java/org/jooby/internal/netty/NettyWebSocket.java index c2c4b6cbff..070ede05cb 100644 --- a/modules/jooby-netty/src/main/java/org/jooby/internal/netty/NettyWebSocket.java +++ b/modules/jooby-netty/src/main/java/org/jooby/internal/netty/NettyWebSocket.java @@ -208,11 +208,13 @@ import java.io.IOException; import java.nio.ByteBuffer; +import java.nio.charset.StandardCharsets; import java.util.Optional; import java.util.concurrent.CountDownLatch; import java.util.function.BiConsumer; import java.util.function.Consumer; +import io.netty.handler.codec.http.websocketx.*; import org.jooby.WebSocket; import org.jooby.WebSocket.OnError; import org.jooby.WebSocket.SuccessCallback; @@ -224,10 +226,6 @@ import io.netty.buffer.Unpooled; import io.netty.channel.ChannelConfig; import io.netty.channel.ChannelHandlerContext; -import io.netty.handler.codec.http.websocketx.BinaryWebSocketFrame; -import io.netty.handler.codec.http.websocketx.CloseWebSocketFrame; -import io.netty.handler.codec.http.websocketx.TextWebSocketFrame; -import io.netty.handler.codec.http.websocketx.WebSocketServerHandshaker; import io.netty.util.Attribute; import io.netty.util.AttributeKey; import io.netty.util.concurrent.Future; @@ -259,6 +257,10 @@ public class NettyWebSocket implements NativeWebSocket { private final CountDownLatch ready = new CountDownLatch(1); + private ByteBuf buffer = null; + + private boolean bufferIsText = false; + public NettyWebSocket(final ChannelHandlerContext ctx, final WebSocketServerHandshaker handshaker, final Consumer handshake) { this.ctx = ctx; @@ -369,10 +371,8 @@ public void hankshake() { public void handle(final Object msg) { ready(); - if (msg instanceof TextWebSocketFrame) { - onTextCallback.accept(((TextWebSocketFrame) msg).text()); - } else if (msg instanceof BinaryWebSocketFrame) { - onBinaryCallback.accept(((BinaryWebSocketFrame) msg).content().nioBuffer()); + if (msg instanceof TextWebSocketFrame || msg instanceof BinaryWebSocketFrame || msg instanceof ContinuationWebSocketFrame){ + handleWebsocketMessage((WebSocketFrame) msg); } else if (msg instanceof CloseWebSocketFrame) { CloseWebSocketFrame closeFrame = ((CloseWebSocketFrame) msg).retain(); int statusCode = closeFrame.statusCode(); @@ -384,6 +384,40 @@ public void handle(final Object msg) { } } + private void handleWebsocketMessage(WebSocketFrame webSocketMessage) { + if (!webSocketMessage.isFinalFragment()) { + if (this.buffer == null) { + if (webSocketMessage instanceof ContinuationWebSocketFrame){ + throw new IllegalStateException("Received ContinuationWebSocketFrame as a first frame of a message."); + } + this.buffer = Unpooled.copiedBuffer(webSocketMessage.content()); + this.bufferIsText = webSocketMessage instanceof TextWebSocketFrame; + } else { + this.buffer.writeBytes(webSocketMessage.content()); + } + } else { + if (this.buffer != null) { + this.buffer.writeBytes(webSocketMessage.content()); + try{ + if (this.bufferIsText) { + onTextCallback.accept(this.buffer.toString(StandardCharsets.UTF_8)); + } else { + onBinaryCallback.accept(this.buffer.nioBuffer()); + } + } finally { + this.buffer = null; + } + } else { + // shortcut to avoid allocating unnecessary copiedBuffers + if (webSocketMessage instanceof TextWebSocketFrame) { + onTextCallback.accept(((TextWebSocketFrame) webSocketMessage).text()); + } else if (webSocketMessage instanceof BinaryWebSocketFrame) { + onBinaryCallback.accept(webSocketMessage.content().nioBuffer()); + } + } + } + } + /** * Make sure hankshake/connect is set. */ diff --git a/modules/jooby-netty/src/test/java/org/jooby/internal/netty/NettyWebSocketTest.java b/modules/jooby-netty/src/test/java/org/jooby/internal/netty/NettyWebSocketTest.java index 8cbc4f1d10..dbd5a05df0 100644 --- a/modules/jooby-netty/src/test/java/org/jooby/internal/netty/NettyWebSocketTest.java +++ b/modules/jooby-netty/src/test/java/org/jooby/internal/netty/NettyWebSocketTest.java @@ -486,6 +486,7 @@ public void handleTextFrame() throws Exception { ready.await(); TextWebSocketFrame frame = unit.get(TextWebSocketFrame.class); + expect(frame.isFinalFragment()).andReturn(true); expect(frame.text()).andReturn("text"); Consumer callback = unit.get(Consumer.class); @@ -517,6 +518,7 @@ public void handleBinaryFrame() throws Exception { expect(buff.nioBuffer()).andReturn(nioBuff); BinaryWebSocketFrame frame = unit.get(BinaryWebSocketFrame.class); + expect(frame.isFinalFragment()).andReturn(true); expect(frame.content()).andReturn(buff); Consumer callback = unit.get(Consumer.class); diff --git a/modules/jooby-pac4j/README.md b/modules/jooby-pac4j/README.md index fceae14ea1..19f4f1ab1d 100644 --- a/modules/jooby-pac4j/README.md +++ b/modules/jooby-pac4j/README.md @@ -1,5 +1,5 @@ -[![Maven Central](https://maven-badges.herokuapp.com/maven-central/org.jooby/jooby-pac4j/badge.svg)](https://maven-badges.herokuapp.com/maven-central/org.jooby/jooby-pac4j) -[![javadoc](https://javadoc.io/badge/org.jooby/jooby-pac4j.svg)](https://javadoc.io/doc/org.jooby/jooby-pac4j/1.5.0) +[![Maven](https://img.shields.io/maven-metadata/v/http/central.maven.org/maven2/org/jooby/jooby-pac4j/maven-metadata.xml.svg)](http://mvnrepository.com/artifact/org.jooby/jooby-pac4j/1.6.6) +[![javadoc](https://javadoc.io/badge/org.jooby/jooby-pac4j.svg)](https://javadoc.io/doc/org.jooby/jooby-pac4j/1.6.6) [![jooby-pac4j website](https://img.shields.io/badge/jooby-pac4j-brightgreen.svg)](http://jooby.org/doc/pac4j) # pac4j @@ -22,7 +22,7 @@ Authentication module via: [Pac4j 1.x](https://github.com/pac4j/pac4j). org.jooby jooby-pac4j - 1.5.0 + 1.6.6 ``` diff --git a/modules/jooby-pac4j/pom.xml b/modules/jooby-pac4j/pom.xml index bc428a279c..90de5eee01 100644 --- a/modules/jooby-pac4j/pom.xml +++ b/modules/jooby-pac4j/pom.xml @@ -5,7 +5,7 @@ org.jooby modules - 1.5.1-SNAPSHOT + 1.6.9 4.0.0 diff --git a/modules/jooby-pac4j2/README.md b/modules/jooby-pac4j2/README.md index a3b1dc9b0a..975bd84ea5 100644 --- a/modules/jooby-pac4j2/README.md +++ b/modules/jooby-pac4j2/README.md @@ -1,5 +1,5 @@ -[![Maven Central](https://maven-badges.herokuapp.com/maven-central/org.jooby/jooby-pac4j2/badge.svg)](https://maven-badges.herokuapp.com/maven-central/org.jooby/jooby-pac4j2) -[![javadoc](https://javadoc.io/badge/org.jooby/jooby-pac4j2.svg)](https://javadoc.io/doc/org.jooby/jooby-pac4j2/1.5.0) +[![Maven](https://img.shields.io/maven-metadata/v/http/central.maven.org/maven2/org/jooby/jooby-pac4j2/maven-metadata.xml.svg)](http://mvnrepository.com/artifact/org.jooby/jooby-pac4j2/1.6.6) +[![javadoc](https://javadoc.io/badge/org.jooby/jooby-pac4j2.svg)](https://javadoc.io/doc/org.jooby/jooby-pac4j2/1.6.6) [![jooby-pac4j2 website](https://img.shields.io/badge/jooby-pac4j2-brightgreen.svg)](http://jooby.org/doc/pac4j2) # pac4j module @@ -19,7 +19,7 @@ Authentication module via: Pac4j 2.x org.jooby jooby-pac4j2 - 1.5.0 + 1.6.6 ``` diff --git a/modules/jooby-pac4j2/pom.xml b/modules/jooby-pac4j2/pom.xml index 91dee44552..51c6a3a98c 100644 --- a/modules/jooby-pac4j2/pom.xml +++ b/modules/jooby-pac4j2/pom.xml @@ -6,7 +6,7 @@ org.jooby modules - 1.5.1-SNAPSHOT + 1.6.9 4.0.0 diff --git a/modules/jooby-pebble/README.md b/modules/jooby-pebble/README.md index c9ef8d5c33..35dfb2b599 100644 --- a/modules/jooby-pebble/README.md +++ b/modules/jooby-pebble/README.md @@ -1,5 +1,5 @@ -[![Maven Central](https://maven-badges.herokuapp.com/maven-central/org.jooby/jooby-pebble/badge.svg)](https://maven-badges.herokuapp.com/maven-central/org.jooby/jooby-pebble) -[![javadoc](https://javadoc.io/badge/org.jooby/jooby-pebble.svg)](https://javadoc.io/doc/org.jooby/jooby-pebble/1.5.0) +[![Maven](https://img.shields.io/maven-metadata/v/http/central.maven.org/maven2/org/jooby/jooby-pebble/maven-metadata.xml.svg)](http://mvnrepository.com/artifact/org.jooby/jooby-pebble/1.6.6) +[![javadoc](https://javadoc.io/badge/org.jooby/jooby-pebble.svg)](https://javadoc.io/doc/org.jooby/jooby-pebble/1.6.6) [![jooby-pebble website](https://img.shields.io/badge/jooby-pebble-brightgreen.svg)](http://jooby.org/doc/pebble) # pebble @@ -16,7 +16,7 @@ org.jooby jooby-pebble - 1.5.0 + 1.6.6 ``` diff --git a/modules/jooby-pebble/pom.xml b/modules/jooby-pebble/pom.xml index ec8aa84aaf..9a3e954bcd 100644 --- a/modules/jooby-pebble/pom.xml +++ b/modules/jooby-pebble/pom.xml @@ -5,7 +5,7 @@ org.jooby modules - 1.5.1-SNAPSHOT + 1.6.9 4.0.0 diff --git a/modules/jooby-quartz/README.md b/modules/jooby-quartz/README.md index d431ccbec1..3b90f75dcb 100644 --- a/modules/jooby-quartz/README.md +++ b/modules/jooby-quartz/README.md @@ -1,5 +1,5 @@ -[![Maven Central](https://maven-badges.herokuapp.com/maven-central/org.jooby/jooby-quartz/badge.svg)](https://maven-badges.herokuapp.com/maven-central/org.jooby/jooby-quartz) -[![javadoc](https://javadoc.io/badge/org.jooby/jooby-quartz.svg)](https://javadoc.io/doc/org.jooby/jooby-quartz/1.5.0) +[![Maven](https://img.shields.io/maven-metadata/v/http/central.maven.org/maven2/org/jooby/jooby-quartz/maven-metadata.xml.svg)](http://mvnrepository.com/artifact/org.jooby/jooby-quartz/1.6.6) +[![javadoc](https://javadoc.io/badge/org.jooby/jooby-quartz.svg)](https://javadoc.io/doc/org.jooby/jooby-quartz/1.6.6) [![jooby-quartz website](https://img.shields.io/badge/jooby-quartz-brightgreen.svg)](http://jooby.org/doc/quartz) # quartz @@ -11,7 +11,7 @@ Cron triggers, job scheduling and async processing via [Quartz](http://quartz-sc org.jooby jooby-quartz - 1.5.0 + 1.6.6 ``` diff --git a/modules/jooby-quartz/pom.xml b/modules/jooby-quartz/pom.xml index 27da25eff2..52f3573da8 100644 --- a/modules/jooby-quartz/pom.xml +++ b/modules/jooby-quartz/pom.xml @@ -5,7 +5,7 @@ org.jooby modules - 1.5.1-SNAPSHOT + 1.6.9 4.0.0 diff --git a/modules/jooby-querydsl/README.md b/modules/jooby-querydsl/README.md index c4394c7fc4..50a01e9b76 100644 --- a/modules/jooby-querydsl/README.md +++ b/modules/jooby-querydsl/README.md @@ -1,5 +1,5 @@ -[![Maven Central](https://maven-badges.herokuapp.com/maven-central/org.jooby/jooby-querydsl/badge.svg)](https://maven-badges.herokuapp.com/maven-central/org.jooby/jooby-querydsl) -[![javadoc](https://javadoc.io/badge/org.jooby/jooby-querydsl.svg)](https://javadoc.io/doc/org.jooby/jooby-querydsl/1.5.0) +[![Maven](https://img.shields.io/maven-metadata/v/http/central.maven.org/maven2/org/jooby/jooby-querydsl/maven-metadata.xml.svg)](http://mvnrepository.com/artifact/org.jooby/jooby-querydsl/1.6.6) +[![javadoc](https://javadoc.io/badge/org.jooby/jooby-querydsl.svg)](https://javadoc.io/doc/org.jooby/jooby-querydsl/1.6.6) [![jooby-querydsl website](https://img.shields.io/badge/jooby-querydsl-brightgreen.svg)](http://jooby.org/doc/querydsl) # queryDSL @@ -17,7 +17,7 @@ SQL abstraction provided by QueryDSL using org.jooby jooby-querydsl - 1.5.0 + 1.6.6 ``` diff --git a/modules/jooby-querydsl/pom.xml b/modules/jooby-querydsl/pom.xml index 1f6f5a26e3..acba22394a 100644 --- a/modules/jooby-querydsl/pom.xml +++ b/modules/jooby-querydsl/pom.xml @@ -4,7 +4,7 @@ modules org.jooby - 1.5.1-SNAPSHOT + 1.6.9 4.0.0 diff --git a/modules/jooby-reactor/README.md b/modules/jooby-reactor/README.md index 70991445d5..4552bcd46c 100644 --- a/modules/jooby-reactor/README.md +++ b/modules/jooby-reactor/README.md @@ -1,5 +1,5 @@ -[![Maven Central](https://maven-badges.herokuapp.com/maven-central/org.jooby/jooby-reactor/badge.svg)](https://maven-badges.herokuapp.com/maven-central/org.jooby/jooby-reactor) -[![javadoc](https://javadoc.io/badge/org.jooby/jooby-reactor.svg)](https://javadoc.io/doc/org.jooby/jooby-reactor/1.5.0) +[![Maven](https://img.shields.io/maven-metadata/v/http/central.maven.org/maven2/org/jooby/jooby-reactor/maven-metadata.xml.svg)](http://mvnrepository.com/artifact/org.jooby/jooby-reactor/1.6.6) +[![javadoc](https://javadoc.io/badge/org.jooby/jooby-reactor.svg)](https://javadoc.io/doc/org.jooby/jooby-reactor/1.6.6) [![jooby-reactor website](https://img.shields.io/badge/jooby-reactor-brightgreen.svg)](http://jooby.org/doc/reactor) # reactor @@ -11,7 +11,7 @@ org.jooby jooby-reactor - 1.5.0 + 1.6.6 ``` diff --git a/modules/jooby-reactor/pom.xml b/modules/jooby-reactor/pom.xml index 8733c1d138..93eba99a84 100644 --- a/modules/jooby-reactor/pom.xml +++ b/modules/jooby-reactor/pom.xml @@ -5,7 +5,7 @@ org.jooby modules - 1.5.1-SNAPSHOT + 1.6.9 4.0.0 diff --git a/modules/jooby-requery/README.md b/modules/jooby-requery/README.md index f814f2cd37..6a3c9da432 100644 --- a/modules/jooby-requery/README.md +++ b/modules/jooby-requery/README.md @@ -1,5 +1,5 @@ -[![Maven Central](https://maven-badges.herokuapp.com/maven-central/org.jooby/jooby-requery/badge.svg)](https://maven-badges.herokuapp.com/maven-central/org.jooby/jooby-requery) -[![javadoc](https://javadoc.io/badge/org.jooby/jooby-requery.svg)](https://javadoc.io/doc/org.jooby/jooby-requery/1.5.0) +[![Maven](https://img.shields.io/maven-metadata/v/http/central.maven.org/maven2/org/jooby/jooby-requery/maven-metadata.xml.svg)](http://mvnrepository.com/artifact/org.jooby/jooby-requery/1.6.6) +[![javadoc](https://javadoc.io/badge/org.jooby/jooby-requery.svg)](https://javadoc.io/doc/org.jooby/jooby-requery/1.6.6) [![jooby-requery website](https://img.shields.io/badge/jooby-requery-brightgreen.svg)](http://jooby.org/doc/requery) # requery @@ -15,7 +15,7 @@ Safe, clean and efficient database access via { + + private Class type; + + private Registry registry; + + public ProxyEntityStateListener(Class type) { + this.type = type; + } + + @Override public void accept(Registry registry) { + this.registry = registry; + } + + private EntityStateListener forwarding() { + if (registry == null) { + throw new IllegalStateException("Registry was not set"); + } + return (EntityStateListener) registry.require(type); + } + + @Override public void postDelete(Object entity) { + forwarding().postDelete(entity); + } + + @Override public void postInsert(Object entity) { + forwarding().postInsert(entity); + } + + @Override public void postLoad(Object entity) { + forwarding().postLoad(entity); + } + + @Override public void postUpdate(Object entity) { + forwarding().postUpdate(entity); + } + + @Override public void preDelete(Object entity) { + forwarding().preDelete(entity); + } + + @Override public void preInsert(Object entity) { + forwarding().preInsert(entity); + } + + @Override public void preUpdate(Object entity) { + forwarding().preUpdate(entity); + } +} diff --git a/modules/jooby-requery/src/main/java/org/jooby/requery/ProxyStatementListener.java b/modules/jooby-requery/src/main/java/org/jooby/requery/ProxyStatementListener.java new file mode 100644 index 0000000000..db25ad6f30 --- /dev/null +++ b/modules/jooby-requery/src/main/java/org/jooby/requery/ProxyStatementListener.java @@ -0,0 +1,259 @@ +/** + * Apache License + * Version 2.0, January 2004 + * http://www.apache.org/licenses/ + * + * TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + * + * 1. Definitions. + * + * "License" shall mean the terms and conditions for use, reproduction, + * and distribution as defined by Sections 1 through 9 of this document. + * + * "Licensor" shall mean the copyright owner or entity authorized by + * the copyright owner that is granting the License. + * + * "Legal Entity" shall mean the union of the acting entity and all + * other entities that control, are controlled by, or are under common + * control with that entity. For the purposes of this definition, + * "control" means (i) the power, direct or indirect, to cause the + * direction or management of such entity, whether by contract or + * otherwise, or (ii) ownership of fifty percent (50%) or more of the + * outstanding shares, or (iii) beneficial ownership of such entity. + * + * "You" (or "Your") shall mean an individual or Legal Entity + * exercising permissions granted by this License. + * + * "Source" form shall mean the preferred form for making modifications, + * including but not limited to software source code, documentation + * source, and configuration files. + * + * "Object" form shall mean any form resulting from mechanical + * transformation or translation of a Source form, including but + * not limited to compiled object code, generated documentation, + * and conversions to other media types. + * + * "Work" shall mean the work of authorship, whether in Source or + * Object form, made available under the License, as indicated by a + * copyright notice that is included in or attached to the work + * (an example is provided in the Appendix below). + * + * "Derivative Works" shall mean any work, whether in Source or Object + * form, that is based on (or derived from) the Work and for which the + * editorial revisions, annotations, elaborations, or other modifications + * represent, as a whole, an original work of authorship. For the purposes + * of this License, Derivative Works shall not include works that remain + * separable from, or merely link (or bind by name) to the interfaces of, + * the Work and Derivative Works thereof. + * + * "Contribution" shall mean any work of authorship, including + * the original version of the Work and any modifications or additions + * to that Work or Derivative Works thereof, that is intentionally + * submitted to Licensor for inclusion in the Work by the copyright owner + * or by an individual or Legal Entity authorized to submit on behalf of + * the copyright owner. For the purposes of this definition, "submitted" + * means any form of electronic, verbal, or written communication sent + * to the Licensor or its representatives, including but not limited to + * communication on electronic mailing lists, source code control systems, + * and issue tracking systems that are managed by, or on behalf of, the + * Licensor for the purpose of discussing and improving the Work, but + * excluding communication that is conspicuously marked or otherwise + * designated in writing by the copyright owner as "Not a Contribution." + * + * "Contributor" shall mean Licensor and any individual or Legal Entity + * on behalf of whom a Contribution has been received by Licensor and + * subsequently incorporated within the Work. + * + * 2. Grant of Copyright License. Subject to the terms and conditions of + * this License, each Contributor hereby grants to You a perpetual, + * worldwide, non-exclusive, no-charge, royalty-free, irrevocable + * copyright license to reproduce, prepare Derivative Works of, + * publicly display, publicly perform, sublicense, and distribute the + * Work and such Derivative Works in Source or Object form. + * + * 3. Grant of Patent License. Subject to the terms and conditions of + * this License, each Contributor hereby grants to You a perpetual, + * worldwide, non-exclusive, no-charge, royalty-free, irrevocable + * (except as stated in this section) patent license to make, have made, + * use, offer to sell, sell, import, and otherwise transfer the Work, + * where such license applies only to those patent claims licensable + * by such Contributor that are necessarily infringed by their + * Contribution(s) alone or by combination of their Contribution(s) + * with the Work to which such Contribution(s) was submitted. If You + * institute patent litigation against any entity (including a + * cross-claim or counterclaim in a lawsuit) alleging that the Work + * or a Contribution incorporated within the Work constitutes direct + * or contributory patent infringement, then any patent licenses + * granted to You under this License for that Work shall terminate + * as of the date such litigation is filed. + * + * 4. Redistribution. You may reproduce and distribute copies of the + * Work or Derivative Works thereof in any medium, with or without + * modifications, and in Source or Object form, provided that You + * meet the following conditions: + * + * (a) You must give any other recipients of the Work or + * Derivative Works a copy of this License; and + * + * (b) You must cause any modified files to carry prominent notices + * stating that You changed the files; and + * + * (c) You must retain, in the Source form of any Derivative Works + * that You distribute, all copyright, patent, trademark, and + * attribution notices from the Source form of the Work, + * excluding those notices that do not pertain to any part of + * the Derivative Works; and + * + * (d) If the Work includes a "NOTICE" text file as part of its + * distribution, then any Derivative Works that You distribute must + * include a readable copy of the attribution notices contained + * within such NOTICE file, excluding those notices that do not + * pertain to any part of the Derivative Works, in at least one + * of the following places: within a NOTICE text file distributed + * as part of the Derivative Works; within the Source form or + * documentation, if provided along with the Derivative Works; or, + * within a display generated by the Derivative Works, if and + * wherever such third-party notices normally appear. The contents + * of the NOTICE file are for informational purposes only and + * do not modify the License. You may add Your own attribution + * notices within Derivative Works that You distribute, alongside + * or as an addendum to the NOTICE text from the Work, provided + * that such additional attribution notices cannot be construed + * as modifying the License. + * + * You may add Your own copyright statement to Your modifications and + * may provide additional or different license terms and conditions + * for use, reproduction, or distribution of Your modifications, or + * for any such Derivative Works as a whole, provided Your use, + * reproduction, and distribution of the Work otherwise complies with + * the conditions stated in this License. + * + * 5. Submission of Contributions. Unless You explicitly state otherwise, + * any Contribution intentionally submitted for inclusion in the Work + * by You to the Licensor shall be under the terms and conditions of + * this License, without any additional terms or conditions. + * Notwithstanding the above, nothing herein shall supersede or modify + * the terms of any separate license agreement you may have executed + * with Licensor regarding such Contributions. + * + * 6. Trademarks. This License does not grant permission to use the trade + * names, trademarks, service marks, or product names of the Licensor, + * except as required for reasonable and customary use in describing the + * origin of the Work and reproducing the content of the NOTICE file. + * + * 7. Disclaimer of Warranty. Unless required by applicable law or + * agreed to in writing, Licensor provides the Work (and each + * Contributor provides its Contributions) on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied, including, without limitation, any warranties or conditions + * of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + * PARTICULAR PURPOSE. You are solely responsible for determining the + * appropriateness of using or redistributing the Work and assume any + * risks associated with Your exercise of permissions under this License. + * + * 8. Limitation of Liability. In no event and under no legal theory, + * whether in tort (including negligence), contract, or otherwise, + * unless required by applicable law (such as deliberate and grossly + * negligent acts) or agreed to in writing, shall any Contributor be + * liable to You for damages, including any direct, indirect, special, + * incidental, or consequential damages of any character arising as a + * result of this License or out of the use or inability to use the + * Work (including but not limited to damages for loss of goodwill, + * work stoppage, computer failure or malfunction, or any and all + * other commercial damages or losses), even if such Contributor + * has been advised of the possibility of such damages. + * + * 9. Accepting Warranty or Additional Liability. While redistributing + * the Work or Derivative Works thereof, You may choose to offer, + * and charge a fee for, acceptance of support, warranty, indemnity, + * or other liability obligations and/or rights consistent with this + * License. However, in accepting such obligations, You may act only + * on Your own behalf and on Your sole responsibility, not on behalf + * of any other Contributor, and only if You agree to indemnify, + * defend, and hold each Contributor harmless for any liability + * incurred by, or claims asserted against, such Contributor by reason + * of your accepting any such warranty or additional liability. + * + * END OF TERMS AND CONDITIONS + * + * APPENDIX: How to apply the Apache License to your work. + * + * To apply the Apache License to your work, attach the following + * boilerplate notice, with the fields enclosed by brackets "{}" + * replaced with your own identifying information. (Don't include + * the brackets!) The text should be enclosed in the appropriate + * comment syntax for the file format. We also recommend that a + * file or class name and description of purpose be included on the + * same "printed page" as the copyright notice for easier + * identification within third-party archives. + * + * Copyright 2014 Edgar Espina + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jooby.requery; + +import io.requery.sql.BoundParameters; +import io.requery.sql.StatementListener; +import org.jooby.Registry; + +import java.sql.Statement; +import java.util.function.Consumer; + +class ProxyStatementListener implements StatementListener, Consumer { + + private Class type; + + private Registry registry; + + public ProxyStatementListener(Class type) { + this.type = type; + } + + private StatementListener forwarding() { + if (registry == null) { + throw new IllegalStateException("Registry was not set"); + } + return (StatementListener) registry.require(type); + } + + @Override + public void beforeExecuteUpdate(Statement statement, String sql, BoundParameters parameters) { + forwarding().beforeExecuteUpdate(statement, sql, parameters); + } + + @Override public void afterExecuteUpdate(Statement statement, int count) { + forwarding().afterExecuteUpdate(statement, count); + } + + @Override public void beforeExecuteBatchUpdate(Statement statement, String sql) { + forwarding().beforeExecuteBatchUpdate(statement, sql); + } + + @Override public void afterExecuteBatchUpdate(Statement statement, int[] count) { + forwarding().afterExecuteBatchUpdate(statement, count); + } + + @Override + public void beforeExecuteQuery(Statement statement, String sql, BoundParameters parameters) { + forwarding().beforeExecuteQuery(statement, sql, parameters); + } + + @Override public void afterExecuteQuery(Statement statement) { + forwarding().afterExecuteQuery(statement); + } + + @Override public void accept(Registry registry) { + this.registry = registry; + } +} diff --git a/modules/jooby-requery/src/main/java/org/jooby/requery/ProxyTransactionListener.java b/modules/jooby-requery/src/main/java/org/jooby/requery/ProxyTransactionListener.java new file mode 100644 index 0000000000..9c28e9085d --- /dev/null +++ b/modules/jooby-requery/src/main/java/org/jooby/requery/ProxyTransactionListener.java @@ -0,0 +1,259 @@ +/** + * Apache License + * Version 2.0, January 2004 + * http://www.apache.org/licenses/ + * + * TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + * + * 1. Definitions. + * + * "License" shall mean the terms and conditions for use, reproduction, + * and distribution as defined by Sections 1 through 9 of this document. + * + * "Licensor" shall mean the copyright owner or entity authorized by + * the copyright owner that is granting the License. + * + * "Legal Entity" shall mean the union of the acting entity and all + * other entities that control, are controlled by, or are under common + * control with that entity. For the purposes of this definition, + * "control" means (i) the power, direct or indirect, to cause the + * direction or management of such entity, whether by contract or + * otherwise, or (ii) ownership of fifty percent (50%) or more of the + * outstanding shares, or (iii) beneficial ownership of such entity. + * + * "You" (or "Your") shall mean an individual or Legal Entity + * exercising permissions granted by this License. + * + * "Source" form shall mean the preferred form for making modifications, + * including but not limited to software source code, documentation + * source, and configuration files. + * + * "Object" form shall mean any form resulting from mechanical + * transformation or translation of a Source form, including but + * not limited to compiled object code, generated documentation, + * and conversions to other media types. + * + * "Work" shall mean the work of authorship, whether in Source or + * Object form, made available under the License, as indicated by a + * copyright notice that is included in or attached to the work + * (an example is provided in the Appendix below). + * + * "Derivative Works" shall mean any work, whether in Source or Object + * form, that is based on (or derived from) the Work and for which the + * editorial revisions, annotations, elaborations, or other modifications + * represent, as a whole, an original work of authorship. For the purposes + * of this License, Derivative Works shall not include works that remain + * separable from, or merely link (or bind by name) to the interfaces of, + * the Work and Derivative Works thereof. + * + * "Contribution" shall mean any work of authorship, including + * the original version of the Work and any modifications or additions + * to that Work or Derivative Works thereof, that is intentionally + * submitted to Licensor for inclusion in the Work by the copyright owner + * or by an individual or Legal Entity authorized to submit on behalf of + * the copyright owner. For the purposes of this definition, "submitted" + * means any form of electronic, verbal, or written communication sent + * to the Licensor or its representatives, including but not limited to + * communication on electronic mailing lists, source code control systems, + * and issue tracking systems that are managed by, or on behalf of, the + * Licensor for the purpose of discussing and improving the Work, but + * excluding communication that is conspicuously marked or otherwise + * designated in writing by the copyright owner as "Not a Contribution." + * + * "Contributor" shall mean Licensor and any individual or Legal Entity + * on behalf of whom a Contribution has been received by Licensor and + * subsequently incorporated within the Work. + * + * 2. Grant of Copyright License. Subject to the terms and conditions of + * this License, each Contributor hereby grants to You a perpetual, + * worldwide, non-exclusive, no-charge, royalty-free, irrevocable + * copyright license to reproduce, prepare Derivative Works of, + * publicly display, publicly perform, sublicense, and distribute the + * Work and such Derivative Works in Source or Object form. + * + * 3. Grant of Patent License. Subject to the terms and conditions of + * this License, each Contributor hereby grants to You a perpetual, + * worldwide, non-exclusive, no-charge, royalty-free, irrevocable + * (except as stated in this section) patent license to make, have made, + * use, offer to sell, sell, import, and otherwise transfer the Work, + * where such license applies only to those patent claims licensable + * by such Contributor that are necessarily infringed by their + * Contribution(s) alone or by combination of their Contribution(s) + * with the Work to which such Contribution(s) was submitted. If You + * institute patent litigation against any entity (including a + * cross-claim or counterclaim in a lawsuit) alleging that the Work + * or a Contribution incorporated within the Work constitutes direct + * or contributory patent infringement, then any patent licenses + * granted to You under this License for that Work shall terminate + * as of the date such litigation is filed. + * + * 4. Redistribution. You may reproduce and distribute copies of the + * Work or Derivative Works thereof in any medium, with or without + * modifications, and in Source or Object form, provided that You + * meet the following conditions: + * + * (a) You must give any other recipients of the Work or + * Derivative Works a copy of this License; and + * + * (b) You must cause any modified files to carry prominent notices + * stating that You changed the files; and + * + * (c) You must retain, in the Source form of any Derivative Works + * that You distribute, all copyright, patent, trademark, and + * attribution notices from the Source form of the Work, + * excluding those notices that do not pertain to any part of + * the Derivative Works; and + * + * (d) If the Work includes a "NOTICE" text file as part of its + * distribution, then any Derivative Works that You distribute must + * include a readable copy of the attribution notices contained + * within such NOTICE file, excluding those notices that do not + * pertain to any part of the Derivative Works, in at least one + * of the following places: within a NOTICE text file distributed + * as part of the Derivative Works; within the Source form or + * documentation, if provided along with the Derivative Works; or, + * within a display generated by the Derivative Works, if and + * wherever such third-party notices normally appear. The contents + * of the NOTICE file are for informational purposes only and + * do not modify the License. You may add Your own attribution + * notices within Derivative Works that You distribute, alongside + * or as an addendum to the NOTICE text from the Work, provided + * that such additional attribution notices cannot be construed + * as modifying the License. + * + * You may add Your own copyright statement to Your modifications and + * may provide additional or different license terms and conditions + * for use, reproduction, or distribution of Your modifications, or + * for any such Derivative Works as a whole, provided Your use, + * reproduction, and distribution of the Work otherwise complies with + * the conditions stated in this License. + * + * 5. Submission of Contributions. Unless You explicitly state otherwise, + * any Contribution intentionally submitted for inclusion in the Work + * by You to the Licensor shall be under the terms and conditions of + * this License, without any additional terms or conditions. + * Notwithstanding the above, nothing herein shall supersede or modify + * the terms of any separate license agreement you may have executed + * with Licensor regarding such Contributions. + * + * 6. Trademarks. This License does not grant permission to use the trade + * names, trademarks, service marks, or product names of the Licensor, + * except as required for reasonable and customary use in describing the + * origin of the Work and reproducing the content of the NOTICE file. + * + * 7. Disclaimer of Warranty. Unless required by applicable law or + * agreed to in writing, Licensor provides the Work (and each + * Contributor provides its Contributions) on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied, including, without limitation, any warranties or conditions + * of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + * PARTICULAR PURPOSE. You are solely responsible for determining the + * appropriateness of using or redistributing the Work and assume any + * risks associated with Your exercise of permissions under this License. + * + * 8. Limitation of Liability. In no event and under no legal theory, + * whether in tort (including negligence), contract, or otherwise, + * unless required by applicable law (such as deliberate and grossly + * negligent acts) or agreed to in writing, shall any Contributor be + * liable to You for damages, including any direct, indirect, special, + * incidental, or consequential damages of any character arising as a + * result of this License or out of the use or inability to use the + * Work (including but not limited to damages for loss of goodwill, + * work stoppage, computer failure or malfunction, or any and all + * other commercial damages or losses), even if such Contributor + * has been advised of the possibility of such damages. + * + * 9. Accepting Warranty or Additional Liability. While redistributing + * the Work or Derivative Works thereof, You may choose to offer, + * and charge a fee for, acceptance of support, warranty, indemnity, + * or other liability obligations and/or rights consistent with this + * License. However, in accepting such obligations, You may act only + * on Your own behalf and on Your sole responsibility, not on behalf + * of any other Contributor, and only if You agree to indemnify, + * defend, and hold each Contributor harmless for any liability + * incurred by, or claims asserted against, such Contributor by reason + * of your accepting any such warranty or additional liability. + * + * END OF TERMS AND CONDITIONS + * + * APPENDIX: How to apply the Apache License to your work. + * + * To apply the Apache License to your work, attach the following + * boilerplate notice, with the fields enclosed by brackets "{}" + * replaced with your own identifying information. (Don't include + * the brackets!) The text should be enclosed in the appropriate + * comment syntax for the file format. We also recommend that a + * file or class name and description of purpose be included on the + * same "printed page" as the copyright notice for easier + * identification within third-party archives. + * + * Copyright 2014 Edgar Espina + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jooby.requery; + +import io.requery.TransactionIsolation; +import io.requery.TransactionListener; +import io.requery.meta.Type; +import io.requery.sql.EntityStateListener; +import org.jooby.Registry; + +import java.util.Set; +import java.util.function.Consumer; + +class ProxyTransactionListener implements TransactionListener, Consumer { + + private Class type; + + private Registry registry; + + public ProxyTransactionListener(Class type) { + this.type = type; + } + + @Override public void accept(Registry registry) { + this.registry = registry; + } + + private TransactionListener forwarding() { + if (registry == null) { + throw new IllegalStateException("Registry was not set"); + } + return (TransactionListener) registry.require(type); + } + + @Override public void beforeBegin(TransactionIsolation isolation) { + forwarding().beforeBegin(isolation); + } + + @Override public void afterBegin(TransactionIsolation isolation) { + forwarding().afterBegin(isolation); + } + + @Override public void beforeCommit(Set> types) { + forwarding().beforeCommit(types); + } + + @Override public void afterCommit(Set> types) { + forwarding().afterCommit(types); + } + + @Override public void beforeRollback(Set> types) { + forwarding().beforeRollback(types); + } + + @Override public void afterRollback(Set> types) { + forwarding().afterRollback(types); + } +} diff --git a/modules/jooby-requery/src/main/java/org/jooby/requery/Requery.java b/modules/jooby-requery/src/main/java/org/jooby/requery/Requery.java index 03cbf337a4..d79a80d48f 100644 --- a/modules/jooby-requery/src/main/java/org/jooby/requery/Requery.java +++ b/modules/jooby-requery/src/main/java/org/jooby/requery/Requery.java @@ -205,8 +205,10 @@ import com.google.inject.name.Names; import io.requery.sql.KotlinEntityDataStore; + import static java.util.Objects.requireNonNull; +import java.util.ArrayList; import java.util.LinkedList; import java.util.List; import java.util.NoSuchElementException; @@ -215,6 +217,7 @@ import java.util.function.BiConsumer; import java.util.function.Consumer; import java.util.function.Function; +import java.util.stream.Collectors; import javax.inject.Provider; import javax.sql.DataSource; @@ -222,6 +225,7 @@ import org.jooby.Env; import org.jooby.Env.ServiceKey; import org.jooby.Jooby.Module; +import org.jooby.Registry; import org.jooby.jdbc.Jdbc; import org.slf4j.bridge.SLF4JBridgeHandler; @@ -588,6 +592,28 @@ public void configure(final Env env, final Config conf, final Binder binder) { if (callback != null) { callback.accept(conf, builder); } + List> proxies = new ArrayList<>(); + statements.stream() + .map(ProxyStatementListener::new) + .forEach(proxy -> { + builder.addStatementListener(proxy); + proxies.add(proxy); + }); + + states.stream() + .map(ProxyEntityStateListener::new) + .forEach(proxy -> { + builder.addEntityStateListener(proxy); + proxies.add(proxy); + }); + + transactions.stream() + .map(ProxyTransactionListener::new) + .forEach(proxy -> { + builder.addTransactionListenerFactory(() -> proxy); + proxies.add(proxy); + }); + Configuration configuration = builder.build(); Object newStore = store.apply(configuration); @@ -611,12 +637,7 @@ public void configure(final Env env, final Config conf, final Binder binder) { env.onStart(registry -> { schema(conf, schema, schema -> new SchemaModifier(dataSource, model).createTables(schema)); - states - .forEach(t -> builder.addEntityStateListener((EntityStateListener) registry.require(t))); - statements - .forEach(t -> builder.addStatementListener((StatementListener) registry.require(t))); - transactions.forEach(t -> builder - .addTransactionListenerFactory(() -> (TransactionListener) registry.require(t))); + proxies.forEach(consumer -> consumer.accept(registry)); }); } diff --git a/modules/jooby-requery/src/test/java/org/jooby/requery/RequeryTest.java b/modules/jooby-requery/src/test/java/org/jooby/requery/RequeryTest.java index 9056df2e49..9cae624f2c 100644 --- a/modules/jooby-requery/src/test/java/org/jooby/requery/RequeryTest.java +++ b/modules/jooby-requery/src/test/java/org/jooby/requery/RequeryTest.java @@ -28,16 +28,21 @@ import io.requery.sql.StatementListener; import io.requery.sql.TableCreationMode; import io.requery.util.function.Supplier; + import static org.easymock.EasyMock.eq; import static org.easymock.EasyMock.expect; import static org.easymock.EasyMock.isA; + import org.jooby.Env; import org.jooby.Env.ServiceKey; import org.jooby.Registry; import org.jooby.test.MockUnit; import org.jooby.test.MockUnit.Block; import org.jooby.funzy.Throwing; + import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + import org.junit.Test; import org.junit.runner.RunWith; import org.powermock.core.classloader.annotations.PrepareForTest; @@ -339,10 +344,8 @@ public void preUpdate(final Object entity) { .expect(eds) .expect(unit -> { ConfigurationBuilder builder = unit.get(ConfigurationBuilder.class); - expect(builder.addEntityStateListener(listener)).andReturn(builder); - - Registry registry = unit.get(Registry.class); - expect(registry.require(MyListener.class)).andReturn(listener); + expect(builder.addEntityStateListener(isA(ProxyEntityStateListener.class))) + .andReturn(builder); }) .run(unit -> { new Requery(unit.get(EntityModel.class)) @@ -396,10 +399,8 @@ public void afterExecuteQuery(final Statement statement) { .expect(eds) .expect(unit -> { ConfigurationBuilder builder = unit.get(ConfigurationBuilder.class); - expect(builder.addStatementListener(listener)).andReturn(builder); - - Registry registry = unit.get(Registry.class); - expect(registry.require(MyListener.class)).andReturn(listener); + expect(builder.addStatementListener(isA(ProxyStatementListener.class))) + .andReturn(builder); }) .run(unit -> { new Requery(unit.get(EntityModel.class)) @@ -453,9 +454,6 @@ public void afterRollback(final Set> types) { ConfigurationBuilder builder = unit.get(ConfigurationBuilder.class); expect(builder.addTransactionListenerFactory(unit.capture(Supplier.class))) .andReturn(builder); - - Registry registry = unit.get(Registry.class); - expect(registry.require(MyListener.class)).andReturn(listener); }) .run(unit -> { new Requery(unit.get(EntityModel.class)) @@ -464,7 +462,8 @@ public void afterRollback(final Set> types) { }, unit -> { unit.captured(Throwing.Consumer.class).iterator().next() .accept(unit.get(Registry.class)); - assertEquals(listener, unit.captured(Supplier.class).iterator().next().get()); + assertTrue(unit.captured(Supplier.class).iterator().next() + .get() instanceof ProxyTransactionListener); }); } diff --git a/modules/jooby-rocker/README.md b/modules/jooby-rocker/README.md index 6b7974e67c..45f0334f86 100644 --- a/modules/jooby-rocker/README.md +++ b/modules/jooby-rocker/README.md @@ -1,5 +1,5 @@ -[![Maven Central](https://maven-badges.herokuapp.com/maven-central/org.jooby/jooby-rocker/badge.svg)](https://maven-badges.herokuapp.com/maven-central/org.jooby/jooby-rocker) -[![javadoc](https://javadoc.io/badge/org.jooby/jooby-rocker.svg)](https://javadoc.io/doc/org.jooby/jooby-rocker/1.5.0) +[![Maven](https://img.shields.io/maven-metadata/v/http/central.maven.org/maven2/org/jooby/jooby-rocker/maven-metadata.xml.svg)](http://mvnrepository.com/artifact/org.jooby/jooby-rocker/1.6.6) +[![javadoc](https://javadoc.io/badge/org.jooby/jooby-rocker.svg)](https://javadoc.io/doc/org.jooby/jooby-rocker/1.6.6) [![jooby-rocker website](https://img.shields.io/badge/jooby-rocker-brightgreen.svg)](http://jooby.org/doc/rocker) # rocker @@ -17,7 +17,7 @@ Java 8 optimized, memory efficient, speedy template engine producing statically org.jooby jooby-rocker - 1.5.0 + 1.6.6 ``` diff --git a/modules/jooby-rocker/pom.xml b/modules/jooby-rocker/pom.xml index d58532cadf..8e6222f650 100644 --- a/modules/jooby-rocker/pom.xml +++ b/modules/jooby-rocker/pom.xml @@ -5,7 +5,7 @@ org.jooby modules - 1.5.1-SNAPSHOT + 1.6.9 jooby-rocker jooby-rocker diff --git a/modules/jooby-run/pom.xml b/modules/jooby-run/pom.xml index 5451091af2..78a1253d8f 100644 --- a/modules/jooby-run/pom.xml +++ b/modules/jooby-run/pom.xml @@ -5,7 +5,7 @@ org.jooby modules - 1.5.1-SNAPSHOT + 1.6.9 4.0.0 diff --git a/modules/jooby-run/src/main/java/org/jooby/run/Watcher.java b/modules/jooby-run/src/main/java/org/jooby/run/Watcher.java index 7661972069..a6cd8b9be0 100644 --- a/modules/jooby-run/src/main/java/org/jooby/run/Watcher.java +++ b/modules/jooby-run/src/main/java/org/jooby/run/Watcher.java @@ -203,7 +203,6 @@ */ package org.jooby.run; -import com.sun.nio.file.SensitivityWatchEventModifier; import static java.nio.file.LinkOption.NOFOLLOW_LINKS; import static java.nio.file.StandardWatchEventKinds.ENTRY_CREATE; import static java.nio.file.StandardWatchEventKinds.ENTRY_DELETE; @@ -212,6 +211,8 @@ import java.io.File; import java.io.IOException; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; import java.nio.file.FileSystems; import java.nio.file.FileVisitResult; import java.nio.file.Files; @@ -231,7 +232,18 @@ */ public class Watcher { - private static final WatchEvent.Modifier HIGH = SensitivityWatchEventModifier.HIGH; + private static final WatchEvent.Modifier HIGH = modifier("HIGH"); + + public static WatchEvent.Modifier modifier(String name) { + try { + Class e = Watcher.class.getClassLoader() + .loadClass("com.sun.nio.file.SensitivityWatchEventModifier"); + Method m = e.getDeclaredMethod("valueOf", String.class); + return (WatchEvent.Modifier) m.invoke(null, name); + } catch (ClassNotFoundException | NoSuchMethodException | IllegalAccessException | InvocationTargetException x) { + return () -> name; + } + } private final WatchService watcher; private volatile Map keys; @@ -240,7 +252,7 @@ public class Watcher { private volatile boolean stopped = false; public Watcher(final BiConsumer, Path> listener, final Path... dirs) - throws IOException { + throws IOException { this.watcher = FileSystems.getDefault().newWatchService(); this.keys = new HashMap<>(); this.listener = listener; @@ -275,7 +287,8 @@ public void stop() { * Register the given directory with the WatchService */ private void register(final Path dir) throws IOException { - WatchKey key = dir.register(watcher, new Kind[]{ENTRY_CREATE, ENTRY_DELETE, ENTRY_MODIFY }, HIGH); + WatchKey key = dir + .register(watcher, new Kind[]{ENTRY_CREATE, ENTRY_DELETE, ENTRY_MODIFY}, HIGH); keys.put(key, dir); } diff --git a/modules/jooby-rxjava-jdbc/README.md b/modules/jooby-rxjava-jdbc/README.md index 8ab7f81a08..d67c885578 100644 --- a/modules/jooby-rxjava-jdbc/README.md +++ b/modules/jooby-rxjava-jdbc/README.md @@ -1,5 +1,5 @@ -[![Maven Central](https://maven-badges.herokuapp.com/maven-central/org.jooby/jooby-rxjava-jdbc/badge.svg)](https://maven-badges.herokuapp.com/maven-central/org.jooby/jooby-rxjava-jdbc) -[![javadoc](https://javadoc.io/badge/org.jooby/jooby-rxjava-jdbc.svg)](https://javadoc.io/doc/org.jooby/jooby-rxjava-jdbc/1.5.0) +[![Maven](https://img.shields.io/maven-metadata/v/http/central.maven.org/maven2/org/jooby/jooby-rxjava-jdbc/maven-metadata.xml.svg)](http://mvnrepository.com/artifact/org.jooby/jooby-rxjava-jdbc/1.6.6) +[![javadoc](https://javadoc.io/badge/org.jooby/jooby-rxjava-jdbc.svg)](https://javadoc.io/doc/org.jooby/jooby-rxjava-jdbc/1.6.6) [![jooby-rxjava-jdbc website](https://img.shields.io/badge/jooby-rxjava-jdbc-brightgreen.svg)](http://jooby.org/doc/rxjava-jdbc) # rxjdbc @@ -13,7 +13,7 @@ org.jooby jooby-rxjava-jdbc - 1.5.0 + 1.6.6 ``` diff --git a/modules/jooby-rxjava-jdbc/pom.xml b/modules/jooby-rxjava-jdbc/pom.xml index 2d915e751d..9750d8e606 100644 --- a/modules/jooby-rxjava-jdbc/pom.xml +++ b/modules/jooby-rxjava-jdbc/pom.xml @@ -5,7 +5,7 @@ org.jooby modules - 1.5.1-SNAPSHOT + 1.6.9 4.0.0 diff --git a/modules/jooby-rxjava/README.md b/modules/jooby-rxjava/README.md index 8b46a6915a..f908144d9e 100644 --- a/modules/jooby-rxjava/README.md +++ b/modules/jooby-rxjava/README.md @@ -1,5 +1,5 @@ -[![Maven Central](https://maven-badges.herokuapp.com/maven-central/org.jooby/jooby-rxjava/badge.svg)](https://maven-badges.herokuapp.com/maven-central/org.jooby/jooby-rxjava) -[![javadoc](https://javadoc.io/badge/org.jooby/jooby-rxjava.svg)](https://javadoc.io/doc/org.jooby/jooby-rxjava/1.5.0) +[![Maven](https://img.shields.io/maven-metadata/v/http/central.maven.org/maven2/org/jooby/jooby-rxjava/maven-metadata.xml.svg)](http://mvnrepository.com/artifact/org.jooby/jooby-rxjava/1.6.6) +[![javadoc](https://javadoc.io/badge/org.jooby/jooby-rxjava.svg)](https://javadoc.io/doc/org.jooby/jooby-rxjava/1.6.6) [![jooby-rxjava website](https://img.shields.io/badge/jooby-rxjava-brightgreen.svg)](http://jooby.org/doc/rxjava) # rxjava @@ -13,7 +13,7 @@ RxJava is a Java VM implementation of Reactive Ext org.jooby jooby-rxjava - 1.5.0 + 1.6.6 ``` diff --git a/modules/jooby-rxjava/pom.xml b/modules/jooby-rxjava/pom.xml index 7f58f614c1..db2defa0e8 100644 --- a/modules/jooby-rxjava/pom.xml +++ b/modules/jooby-rxjava/pom.xml @@ -5,7 +5,7 @@ org.jooby modules - 1.5.1-SNAPSHOT + 1.6.9 4.0.0 diff --git a/modules/jooby-scanner/README.md b/modules/jooby-scanner/README.md index 9d792bd354..f149cdfbfb 100644 --- a/modules/jooby-scanner/README.md +++ b/modules/jooby-scanner/README.md @@ -1,5 +1,5 @@ -[![Maven Central](https://maven-badges.herokuapp.com/maven-central/org.jooby/jooby-scanner/badge.svg)](https://maven-badges.herokuapp.com/maven-central/org.jooby/jooby-scanner) -[![javadoc](https://javadoc.io/badge/org.jooby/jooby-scanner.svg)](https://javadoc.io/doc/org.jooby/jooby-scanner/1.5.0) +[![Maven](https://img.shields.io/maven-metadata/v/http/central.maven.org/maven2/org/jooby/jooby-scanner/maven-metadata.xml.svg)](http://mvnrepository.com/artifact/org.jooby/jooby-scanner/1.6.6) +[![javadoc](https://javadoc.io/badge/org.jooby/jooby-scanner.svg)](https://javadoc.io/doc/org.jooby/jooby-scanner/1.6.6) [![jooby-scanner website](https://img.shields.io/badge/jooby-scanner-brightgreen.svg)](http://jooby.org/doc/scanner) # scanner @@ -13,7 +13,7 @@ This module provides `class-path` scanning services for `MVC routes`, `services` org.jooby jooby-scanner - 1.5.0 + 1.6.6 ``` diff --git a/modules/jooby-scanner/pom.xml b/modules/jooby-scanner/pom.xml index 2e959756d4..5c49059510 100644 --- a/modules/jooby-scanner/pom.xml +++ b/modules/jooby-scanner/pom.xml @@ -5,7 +5,7 @@ org.jooby modules - 1.5.1-SNAPSHOT + 1.6.9 4.0.0 @@ -39,8 +39,8 @@ - io.github.lukehutch - fast-classpath-scanner + io.github.classgraph + classgraph diff --git a/modules/jooby-scanner/src/main/java/org/jooby/scanner/Scanner.java b/modules/jooby-scanner/src/main/java/org/jooby/scanner/Scanner.java index 7727b2a36a..ebb8317bce 100644 --- a/modules/jooby-scanner/src/main/java/org/jooby/scanner/Scanner.java +++ b/modules/jooby-scanner/src/main/java/org/jooby/scanner/Scanner.java @@ -211,14 +211,16 @@ import com.google.inject.Binder; import com.google.inject.Module; import com.typesafe.config.Config; -import io.github.lukehutch.fastclasspathscanner.FastClasspathScanner; -import io.github.lukehutch.fastclasspathscanner.scanner.ScanResult; +import io.github.classgraph.ClassGraph; +import io.github.classgraph.ClassInfo; +import io.github.classgraph.ScanResult; import org.jooby.Env; import org.jooby.Jooby; import org.jooby.Router; import org.jooby.funzy.Throwing; -import static org.jooby.funzy.Throwing.throwingConsumer; + import static org.jooby.funzy.Throwing.throwingSupplier; + import org.jooby.mvc.Path; import javax.annotation.PostConstruct; @@ -399,7 +401,8 @@ public void configure(final Env env, final Config conf, final Binder binder) { Set spec = Sets.newLinkedHashSet(packages); serviceTypes.forEach(it -> spec.add(it.getPackage().getName())); - FastClasspathScanner scanner = new FastClasspathScanner(spec.toArray(new String[spec.size()])); + ClassGraph scanner = new ClassGraph().enableAllInfo() + .whitelistPackages(spec.toArray(new String[spec.size()])); Router routes = env.router(); @@ -415,24 +418,26 @@ public void configure(final Env env, final Config conf, final Binder binder) { env.lifeCycle(klass); }; - ScanResult result = scanner.scan(conf.getInt("runtime.processors") + 1); + ScanResult result = scanner.scan(); - Predicate inPackage = name -> packages.stream() - .anyMatch(name::startsWith); + Predicate inPackage = c -> packages.stream() + .anyMatch(c.getName()::startsWith); /** Controllers: */ - result.getNamesOfClassesWithAnnotation(Path.class) + result.getClassesWithAnnotation(Path.class.getName()) .stream() .filter(once) + .map(ClassInfo::getName) .map(loadClass) .filter(C) .forEach(routes::use); String mainClass = conf.getString("application.class"); /** Apps: */ - result.getNamesOfSubclassesOf(Jooby.class) + result.getSubclasses(Jooby.class.getName()) .stream() .filter(once) + .map(ClassInfo::getName) .filter(name -> !name.equals(mainClass)) .map(loadClass) .filter(C) @@ -441,9 +446,10 @@ public void configure(final Env env, final Config conf, final Binder binder) { /** Annotated with: */ serviceTypes.stream() .filter(A) - .forEach(a -> result.getNamesOfClassesWithAnnotation(a) + .forEach(a -> result.getClassesWithAnnotation(a.getName()) .stream() .filter(once) + .map(ClassInfo::getName) .map(loadClass) .filter(C) .forEach(bind)); @@ -452,10 +458,11 @@ public void configure(final Env env, final Config conf, final Binder binder) { serviceTypes.stream() .filter(I) .filter(type -> type != Jooby.Module.class && type != Module.class && type != Service.class) - .forEach(i -> result.getNamesOfClassesImplementing(i) + .forEach(i -> result.getClassesImplementing(i.getName()) .stream() .filter(inPackage) .filter(once) + .map(ClassInfo::getName) .map(loadClass) .filter(C) .forEach(bind)); @@ -463,20 +470,22 @@ public void configure(final Env env, final Config conf, final Binder binder) { /** SubclassOf: */ serviceTypes.stream() .filter(S) - .forEach(k -> result.getNamesOfSubclassesOf(k) + .forEach(k -> result.getSubclasses(k.getName()) .stream() .filter(inPackage) .filter(once) + .map(ClassInfo::getName) .map(loadClass) .filter(C) .forEach(bind)); /** Guice modules: */ if (serviceTypes.contains(Module.class)) { - result.getNamesOfClassesImplementing(Module.class) + result.getClassesImplementing(Module.class.getName()) .stream() .filter(inPackage) .filter(once) + .map(ClassInfo::getName) .map(loadClass) .filter(C) .forEach(klass -> ((Module) newObject(klass)).configure(binder)); @@ -485,10 +494,11 @@ public void configure(final Env env, final Config conf, final Binder binder) { /** Guava services: */ if (serviceTypes.contains(Service.class)) { Set> guavaServices = new HashSet<>(); - result.getNamesOfClassesImplementing(Service.class) + result.getClassesImplementing(Service.class.getName()) .stream() .filter(inPackage) .filter(once) + .map(ClassInfo::getName) .map(loadClass) .filter(C) .forEach(guavaServices::add); diff --git a/modules/jooby-scanner/src/test/java/org/jooby/scanner/ScannerTest.java b/modules/jooby-scanner/src/test/java/org/jooby/scanner/ScannerTest.java deleted file mode 100644 index 679e6a14b5..0000000000 --- a/modules/jooby-scanner/src/test/java/org/jooby/scanner/ScannerTest.java +++ /dev/null @@ -1,448 +0,0 @@ -package org.jooby.scanner; - -import app.ns.AbsController; -import app.ns.AbsFoo; -import app.ns.FooApp; -import app.ns.FooController; -import app.ns.FooImpl; -import app.ns.FooModule; -import app.ns.FooSub; -import app.ns.GuavaService; -import app.ns.GuiceModule; -import app.ns.IFoo; -import app.ns.NamedFoo; -import app.ns.SingletonFoo; -import com.google.common.collect.Lists; -import com.google.common.util.concurrent.Service; -import com.google.common.util.concurrent.ServiceManager; -import com.google.inject.Binder; -import com.google.inject.Module; -import com.google.inject.binder.AnnotatedBindingBuilder; -import com.typesafe.config.Config; -import io.github.lukehutch.fastclasspathscanner.FastClasspathScanner; -import io.github.lukehutch.fastclasspathscanner.scanner.ScanResult; -import static org.easymock.EasyMock.expect; -import static org.easymock.EasyMock.isA; -import org.jooby.Env; -import org.jooby.Jooby; -import org.jooby.Registry; -import org.jooby.Router; -import org.jooby.mvc.Path; -import org.jooby.test.MockUnit; -import org.jooby.test.MockUnit.Block; -import org.jooby.funzy.Throwing; -import static org.junit.Assert.assertEquals; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.powermock.core.classloader.annotations.PrepareForTest; -import org.powermock.modules.junit4.PowerMockRunner; - -import javax.inject.Provider; -import java.util.Arrays; -import java.util.List; - -@RunWith(PowerMockRunner.class) -@PrepareForTest({Scanner.class, FastClasspathScanner.class, FooModule.class, ServiceManager.class}) -public class ScannerTest { - - private Block routes = unit -> { - Env env = unit.get(Env.class); - expect(env.router()).andReturn(unit.get(Router.class)); - }; - - private Block runtimeProcessors = unit -> { - expect(unit.get(Config.class).getInt("runtime.processors")).andReturn(1); - }; - - @Test - public void newScanner() throws Exception { - new MockUnit(Env.class, Config.class, Binder.class, Router.class) - .expect(ns("app.ns")) - .expect(runtimeProcessors) - .expect(scanResult("app.ns")) - .expect(routes) - .expect(annotations(Path.class)) - .expect(subClassesOf(Jooby.class)) - .expect(appclass(ScannerTest.class.getName())) - .run(unit -> { - new Scanner() - .configure(unit.get(Env.class), unit.get(Config.class), unit.get(Binder.class)); - }); - } - - @Test - public void newScannerWithSpec() throws Exception { - new MockUnit(Env.class, Config.class, Binder.class, Router.class) - .expect(runtimeProcessors) - .expect(scanResult("test.pkg")) - .expect(routes) - .expect(annotations(Path.class)) - .expect(subClassesOf(Jooby.class)) - .expect(appclass(ScannerTest.class.getName())) - .run(unit -> { - new Scanner("test.pkg") - .configure(unit.get(Env.class), unit.get(Config.class), unit.get(Binder.class)); - }); - } - - @Test - public void scanController() throws Exception { - new MockUnit(Env.class, Config.class, Binder.class, Router.class) - .expect(ns("app.ns")) - .expect(runtimeProcessors) - .expect(scanResult("app.ns")) - .expect(routes) - .expect(annotations(Path.class, FooController.class.getName())) - .expect(subClassesOf(Jooby.class)) - .expect(appclass(ScannerTest.class.getName())) - .expect(unit -> { - Router routes = unit.get(Router.class); - expect(routes.use(FooController.class)).andReturn(null); - }) - .run(unit -> { - new Scanner() - .configure(unit.get(Env.class), unit.get(Config.class), unit.get(Binder.class)); - }); - } - - @Test - public void scanApp() throws Exception { - new MockUnit(Env.class, Config.class, Binder.class, Router.class) - .expect(ns("app.ns")) - .expect(runtimeProcessors) - .expect(scanResult("app.ns")) - .expect(routes) - .expect(annotations(Path.class)) - .expect(subClassesOf(Jooby.class, FooApp.class.getName())) - .expect(appclass(ScannerTest.class.getName())) - .expect(unit -> { - Router routes = unit.get(Router.class); - expect(routes.use(isA(FooApp.class))).andReturn(routes); - }) - .run(unit -> { - new Scanner() - .configure(unit.get(Env.class), unit.get(Config.class), unit.get(Binder.class)); - }); - } - - @SuppressWarnings("unchecked") - @Test - public void scanAnnotation() throws Exception { - new MockUnit(Env.class, Config.class, Binder.class, Router.class) - .expect(ns("app.ns")) - .expect(runtimeProcessors) - .expect(scanResult("app.ns", "javax.inject", "com.google.inject.name")) - .expect(routes) - .expect(annotations(Path.class)) - .expect(subClassesOf(Jooby.class)) - .expect(appclass(ScannerTest.class.getName())) - .expect(annotations(javax.inject.Named.class, NamedFoo.class.getName())) - .expect(annotations(com.google.inject.name.Named.class)) - .expect(unit -> { - Binder binder = unit.get(Binder.class); - - AnnotatedBindingBuilder abb = unit.mock(AnnotatedBindingBuilder.class); - abb.asEagerSingleton(); - expect(binder.bind(NamedFoo.class)).andReturn(abb); - - Env env = unit.get(Env.class); - expect(env.lifeCycle(NamedFoo.class)).andReturn(env); - }) - .run(unit -> { - new Scanner() - .scan(javax.inject.Named.class) - .configure(unit.get(Env.class), unit.get(Config.class), unit.get(Binder.class)); - }); - } - - @SuppressWarnings("unchecked") - @Test - public void scanSingleton() throws Exception { - new MockUnit(Env.class, Config.class, Binder.class, Router.class) - .expect(ns("app.ns")) - .expect(runtimeProcessors) - .expect(scanResult("app.ns", "javax.inject", "com.google.inject")) - .expect(routes) - .expect(annotations(Path.class)) - .expect(subClassesOf(Jooby.class)) - .expect(appclass(ScannerTest.class.getName())) - .expect(annotations(javax.inject.Singleton.class, SingletonFoo.class.getName())) - .expect(annotations(com.google.inject.Singleton.class)) - .expect(unit -> { - Binder binder = unit.get(Binder.class); - - AnnotatedBindingBuilder abb = unit.mock(AnnotatedBindingBuilder.class); - abb.asEagerSingleton(); - expect(binder.bind(SingletonFoo.class)).andReturn(abb); - - Env env = unit.get(Env.class); - expect(env.lifeCycle(SingletonFoo.class)).andReturn(env); - }) - .run(unit -> { - new Scanner() - .scan(javax.inject.Singleton.class) - .configure(unit.get(Env.class), unit.get(Config.class), unit.get(Binder.class)); - }); - } - - @SuppressWarnings("unchecked") - @Test - public void scanImplements() throws Exception { - new MockUnit(Env.class, Config.class, Binder.class, Router.class) - .expect(ns("app.ns")) - .expect(runtimeProcessors) - .expect(scanResult("app.ns")) - .expect(routes) - .expect(annotations(Path.class)) - .expect(subClassesOf(Jooby.class)) - .expect(appclass(ScannerTest.class.getName())) - .expect(implementing(IFoo.class, FooImpl.class.getName())) - .expect(unit -> { - Binder binder = unit.get(Binder.class); - - AnnotatedBindingBuilder abb = unit.mock(AnnotatedBindingBuilder.class); - abb.asEagerSingleton(); - expect(binder.bind(FooImpl.class)).andReturn(abb); - - Env env = unit.get(Env.class); - expect(env.lifeCycle(FooImpl.class)).andReturn(env); - }) - .run(unit -> { - new Scanner() - .scan(IFoo.class) - .configure(unit.get(Env.class), unit.get(Config.class), unit.get(Binder.class)); - }); - } - - @SuppressWarnings("unchecked") - @Test - public void scanSubclass() throws Exception { - new MockUnit(Env.class, Config.class, Binder.class, Router.class) - .expect(ns("app.ns")) - .expect(runtimeProcessors) - .expect(scanResult("app.ns")) - .expect(routes) - .expect(annotations(Path.class)) - .expect(subClassesOf(Jooby.class)) - .expect(appclass(ScannerTest.class.getName())) - .expect(subClassesOf(AbsFoo.class, FooSub.class.getName())) - .expect(unit -> { - Binder binder = unit.get(Binder.class); - - AnnotatedBindingBuilder abb = unit.mock(AnnotatedBindingBuilder.class); - abb.asEagerSingleton(); - expect(binder.bind(FooSub.class)).andReturn(abb); - - Env env = unit.get(Env.class); - expect(env.lifeCycle(FooSub.class)).andReturn(env); - }) - .run(unit -> { - new Scanner() - .scan(AbsFoo.class) - .configure(unit.get(Env.class), unit.get(Config.class), unit.get(Binder.class)); - }); - } - - @Test - public void scanGuiceModule() throws Exception { - new MockUnit(Env.class, Config.class, Binder.class, Router.class) - .expect(ns("app.ns")) - .expect(runtimeProcessors) - .expect(scanResult("app.ns", "com.google.inject")) - .expect(routes) - .expect(annotations(Path.class)) - .expect(subClassesOf(Jooby.class)) - .expect(appclass(ScannerTest.class.getName())) - .expect(implementing(Module.class, GuiceModule.class.getName())) - .expect(unit -> { - Binder binder = unit.get(Binder.class); - expect(binder.bind(GuiceModule.class)).andReturn(null); - }) - .run(unit -> { - new Scanner() - .scan(Module.class) - .configure(unit.get(Env.class), unit.get(Config.class), unit.get(Binder.class)); - }); - } - - @SuppressWarnings("unchecked") - @Test - public void scanGuavaService() throws Exception { - new MockUnit(Env.class, Config.class, Binder.class, Router.class, Registry.class) - .expect(ns("app.ns")) - .expect(runtimeProcessors) - .expect(scanResult("app.ns", "com.google.common.util.concurrent")) - .expect(routes) - .expect(annotations(Path.class)) - .expect(subClassesOf(Jooby.class)) - .expect(appclass(ScannerTest.class.getName())) - .expect(implementing(Service.class, GuavaService.class.getName())) - .expect(unit -> { - Binder binder = unit.get(Binder.class); - AnnotatedBindingBuilder abb = unit.mock(AnnotatedBindingBuilder.class); - abb.asEagerSingleton(); - expect(binder.bind(GuavaService.class)).andReturn(abb); - - AnnotatedBindingBuilder abbsm = unit.mock(AnnotatedBindingBuilder.class); - expect(abbsm.toProvider(unit.capture(Provider.class))).andReturn(abbsm); - expect(binder.bind(ServiceManager.class)).andReturn(abbsm); - - Env env = unit.get(Env.class); - expect(env.onStart(unit.capture(Throwing.Consumer.class))).andReturn(env); - expect(env.onStop(unit.capture(Throwing.Runnable.class))).andReturn(env); - }) - .expect(unit -> { - GuavaService service = unit.mock(GuavaService.class); - Registry registry = unit.get(Registry.class); - expect(registry.require(GuavaService.class)).andReturn(service); - - ServiceManager sm = unit.constructor(ServiceManager.class) - .build(Lists.newArrayList(service)); - - unit.registerMock(ServiceManager.class, sm); - - expect(sm.startAsync()).andReturn(sm); - sm.awaitHealthy(); - - expect(sm.stopAsync()).andReturn(sm); - sm.awaitStopped(); - }) - .run(unit -> { - new Scanner() - .scan(Service.class) - .configure(unit.get(Env.class), unit.get(Config.class), unit.get(Binder.class)); - }, unit -> { - unit.captured(Throwing.Consumer.class).iterator().next().accept(unit.get(Registry.class)); - - assertEquals(unit.get(ServiceManager.class), - unit.captured(Provider.class).iterator().next().get()); - - unit.captured(Throwing.Runnable.class).iterator().next().run(); - }); - } - - @Test - public void scanEmptyGuavaService() throws Exception { - new MockUnit(Env.class, Config.class, Binder.class, Router.class, Registry.class) - .expect(ns("app.ns")) - .expect(runtimeProcessors) - .expect(scanResult("app.ns", "com.google.common.util.concurrent")) - .expect(routes) - .expect(annotations(Path.class)) - .expect(subClassesOf(Jooby.class)) - .expect(appclass(ScannerTest.class.getName())) - .expect(implementing(Service.class)) - .run(unit -> { - new Scanner() - .scan(Service.class) - .configure(unit.get(Env.class), unit.get(Config.class), unit.get(Binder.class)); - }); - } - - @Test - public void scanShouldCreateJustOneController() throws Exception { - new MockUnit(Env.class, Config.class, Binder.class, Router.class) - .expect(ns("app.ns")) - .expect(runtimeProcessors) - .expect(scanResult("app.ns")) - .expect(routes) - .expect( - annotations(Path.class, FooController.class.getName(), FooController.class.getName())) - .expect(subClassesOf(Jooby.class)) - .expect(appclass(ScannerTest.class.getName())) - .expect(unit -> { - Router routes = unit.get(Router.class); - expect(routes.use(FooController.class)).andReturn(null); - }) - .run(unit -> { - new Scanner() - .configure(unit.get(Env.class), unit.get(Config.class), unit.get(Binder.class)); - }); - } - - @Test - public void scanShouldIgnoreAbsClasses() throws Exception { - new MockUnit(Env.class, Config.class, Binder.class, Router.class) - .expect(ns("app.ns")) - .expect(runtimeProcessors) - .expect(scanResult("app.ns")) - .expect(routes) - .expect( - annotations(Path.class, AbsController.class.getName())) - .expect(subClassesOf(Jooby.class)) - .expect(appclass(ScannerTest.class.getName())) - .run(unit -> { - new Scanner() - .configure(unit.get(Env.class), unit.get(Config.class), unit.get(Binder.class)); - }); - } - - @SuppressWarnings("rawtypes") - private Block annotations(final Class type, final String... names) { - return annotations(type, Arrays.asList(names)); - } - - @SuppressWarnings("rawtypes") - private Block annotations(final Class type, final List classes) { - return unit -> { - ScanResult result = unit.get(ScanResult.class); - expect(result.getNamesOfClassesWithAnnotation(type)).andReturn(classes); - }; - } - - @SuppressWarnings("rawtypes") - private Block implementing(final Class type, final String... names) { - return implementing(type, Arrays.asList(names)); - } - - @SuppressWarnings("rawtypes") - private Block implementing(final Class type, final List classes) { - return unit -> { - ScanResult result = unit.get(ScanResult.class); - expect(result.getNamesOfClassesImplementing(type)) - .andReturn(classes); - }; - } - - @SuppressWarnings("rawtypes") - private Block subClassesOf(final Class type, final String... names) { - return subClassesOf(type, Arrays.asList(names)); - } - - @SuppressWarnings("rawtypes") - private Block subClassesOf(final Class type, final List classes) { - return unit -> { - ScanResult result = unit.get(ScanResult.class); - expect(result.getNamesOfSubclassesOf(type)) - .andReturn(classes); - }; - } - - private Block ns(final String pkg) { - return unit -> { - Config conf = unit.get(Config.class); - expect(conf.getString("application.ns")).andReturn(pkg); - }; - } - - private Block appclass(final String main) { - return unit -> { - Config conf = unit.get(Config.class); - expect(conf.getString("application.class")).andReturn(main); - }; - } - - private Block scanResult(final Object... spec) { - return unit -> { - FastClasspathScanner scanner = unit.constructor(FastClasspathScanner.class) - .args(String[].class) - .build(spec); - - ScanResult result = unit.mock(ScanResult.class); - - expect(scanner.scan(2)).andReturn(result); - - unit.registerMock(ScanResult.class, result); - }; - } -} diff --git a/modules/jooby-servlet/README.md b/modules/jooby-servlet/README.md index 66fd90591d..f910d06aee 100644 --- a/modules/jooby-servlet/README.md +++ b/modules/jooby-servlet/README.md @@ -1,5 +1,5 @@ -[![Maven Central](https://maven-badges.herokuapp.com/maven-central/org.jooby/jooby-servlet/badge.svg)](https://maven-badges.herokuapp.com/maven-central/org.jooby/jooby-servlet) -[![javadoc](https://javadoc.io/badge/org.jooby/jooby-servlet.svg)](https://javadoc.io/doc/org.jooby/jooby-servlet/1.5.0) +[![Maven](https://img.shields.io/maven-metadata/v/http/central.maven.org/maven2/org/jooby/jooby-servlet/maven-metadata.xml.svg)](http://mvnrepository.com/artifact/org.jooby/jooby-servlet/1.6.6) +[![javadoc](https://javadoc.io/badge/org.jooby/jooby-servlet.svg)](https://javadoc.io/doc/org.jooby/jooby-servlet/1.6.6) [![jooby-servlet website](https://img.shields.io/badge/jooby-servlet-brightgreen.svg)](http://jooby.org/doc/servlet) # servlets diff --git a/modules/jooby-servlet/pom.xml b/modules/jooby-servlet/pom.xml index 682419dbae..61d9602921 100644 --- a/modules/jooby-servlet/pom.xml +++ b/modules/jooby-servlet/pom.xml @@ -5,7 +5,7 @@ org.jooby modules - 1.5.1-SNAPSHOT + 1.6.9 4.0.0 diff --git a/modules/jooby-servlet/src/main/java/org/jooby/servlet/ServletServletRequest.java b/modules/jooby-servlet/src/main/java/org/jooby/servlet/ServletServletRequest.java index c4943bee11..cea546e372 100644 --- a/modules/jooby-servlet/src/main/java/org/jooby/servlet/ServletServletRequest.java +++ b/modules/jooby-servlet/src/main/java/org/jooby/servlet/ServletServletRequest.java @@ -369,6 +369,20 @@ public List files(final String name) throws IOException { } } + @Override + public List files() throws IOException { + try { + if (multipart) { + return req.getParts().stream() + .map(part -> new ServletUpload(part, tmpdir)) + .collect(Collectors.toList()); + } + return Collections.emptyList(); + } catch (ServletException ex) { + throw new IOException("Unable to get files", ex); + } + } + @Override public InputStream in() throws IOException { return req.getInputStream(); diff --git a/modules/jooby-servlet/src/main/java/org/jooby/servlet/ServletServletResponse.java b/modules/jooby-servlet/src/main/java/org/jooby/servlet/ServletServletResponse.java index bb9e8f35a5..409a33463c 100644 --- a/modules/jooby-servlet/src/main/java/org/jooby/servlet/ServletServletResponse.java +++ b/modules/jooby-servlet/src/main/java/org/jooby/servlet/ServletServletResponse.java @@ -334,8 +334,6 @@ public void end() { } committed = true; } - req = null; - rsp = null; } protected void close() { diff --git a/modules/jooby-sitemap/README.md b/modules/jooby-sitemap/README.md index 99f1b45d58..a41fb19a8c 100644 --- a/modules/jooby-sitemap/README.md +++ b/modules/jooby-sitemap/README.md @@ -1,5 +1,5 @@ -[![Maven Central](https://maven-badges.herokuapp.com/maven-central/org.jooby/jooby-sitemap/badge.svg)](https://maven-badges.herokuapp.com/maven-central/org.jooby/jooby-sitemap) -[![javadoc](https://javadoc.io/badge/org.jooby/jooby-sitemap.svg)](https://javadoc.io/doc/org.jooby/jooby-sitemap/1.5.0) +[![Maven](https://img.shields.io/maven-metadata/v/http/central.maven.org/maven2/org/jooby/jooby-sitemap/maven-metadata.xml.svg)](http://mvnrepository.com/artifact/org.jooby/jooby-sitemap/1.6.6) +[![javadoc](https://javadoc.io/badge/org.jooby/jooby-sitemap.svg)](https://javadoc.io/doc/org.jooby/jooby-sitemap/1.6.6) [![jooby-sitemap website](https://img.shields.io/badge/jooby-sitemap-brightgreen.svg)](http://jooby.org/doc/sitemap) # sitemap @@ -15,7 +15,7 @@ Generate sitemap.xml files org.jooby jooby-sitemap - 1.5.0 + 1.6.6 ``` diff --git a/modules/jooby-sitemap/pom.xml b/modules/jooby-sitemap/pom.xml index ceb17a761b..34d5ddc203 100644 --- a/modules/jooby-sitemap/pom.xml +++ b/modules/jooby-sitemap/pom.xml @@ -5,7 +5,7 @@ org.jooby modules - 1.5.1-SNAPSHOT + 1.6.9 4.0.0 diff --git a/modules/jooby-spymemcached/README.md b/modules/jooby-spymemcached/README.md index 0be71fb679..bd7cd829e2 100644 --- a/modules/jooby-spymemcached/README.md +++ b/modules/jooby-spymemcached/README.md @@ -1,5 +1,5 @@ -[![Maven Central](https://maven-badges.herokuapp.com/maven-central/org.jooby/jooby-spymemcached/badge.svg)](https://maven-badges.herokuapp.com/maven-central/org.jooby/jooby-spymemcached) -[![javadoc](https://javadoc.io/badge/org.jooby/jooby-spymemcached.svg)](https://javadoc.io/doc/org.jooby/jooby-spymemcached/1.5.0) +[![Maven](https://img.shields.io/maven-metadata/v/http/central.maven.org/maven2/org/jooby/jooby-spymemcached/maven-metadata.xml.svg)](http://mvnrepository.com/artifact/org.jooby/jooby-spymemcached/1.6.6) +[![javadoc](https://javadoc.io/badge/org.jooby/jooby-spymemcached.svg)](https://javadoc.io/doc/org.jooby/jooby-spymemcached/1.6.6) [![jooby-spymemcached website](https://img.shields.io/badge/jooby-spymemcached-brightgreen.svg)](http://jooby.org/doc/spymemcached) # spymemcached @@ -15,7 +15,7 @@ Provides memcached access via [SpyMemcached](https://github.com/dustin/java-memc org.jooby jooby-spymemcached - 1.5.0 + 1.6.6 ``` @@ -65,7 +65,7 @@ or programmatically: org.jooby jooby-spymemcached - 1.5.0 + 1.6.6 ``` diff --git a/modules/jooby-spymemcached/pom.xml b/modules/jooby-spymemcached/pom.xml index f9db27dac2..298b8e5207 100644 --- a/modules/jooby-spymemcached/pom.xml +++ b/modules/jooby-spymemcached/pom.xml @@ -5,7 +5,7 @@ org.jooby modules - 1.5.1-SNAPSHOT + 1.6.9 4.0.0 diff --git a/modules/jooby-thymeleaf/README.md b/modules/jooby-thymeleaf/README.md index a6ccc5c9ce..af62c4ea11 100644 --- a/modules/jooby-thymeleaf/README.md +++ b/modules/jooby-thymeleaf/README.md @@ -1,5 +1,5 @@ -[![Maven Central](https://maven-badges.herokuapp.com/maven-central/org.jooby/jooby-thymeleaf/badge.svg)](https://maven-badges.herokuapp.com/maven-central/org.jooby/jooby-thymeleaf) -[![javadoc](https://javadoc.io/badge/org.jooby/jooby-thymeleaf.svg)](https://javadoc.io/doc/org.jooby/jooby-thymeleaf/1.5.0) +[![Maven](https://img.shields.io/maven-metadata/v/http/central.maven.org/maven2/org/jooby/jooby-thymeleaf/maven-metadata.xml.svg)](http://mvnrepository.com/artifact/org.jooby/jooby-thymeleaf/1.6.6) +[![javadoc](https://javadoc.io/badge/org.jooby/jooby-thymeleaf.svg)](https://javadoc.io/doc/org.jooby/jooby-thymeleaf/1.6.6) [![jooby-thymeleaf website](https://img.shields.io/badge/jooby-thymeleaf-brightgreen.svg)](http://jooby.org/doc/thymeleaf) # thymeleaf @@ -11,7 +11,7 @@ org.jooby jooby-thymeleaf - 1.5.0 + 1.6.6 ``` diff --git a/modules/jooby-thymeleaf/pom.xml b/modules/jooby-thymeleaf/pom.xml index 5e409effe5..f45599d93a 100644 --- a/modules/jooby-thymeleaf/pom.xml +++ b/modules/jooby-thymeleaf/pom.xml @@ -5,7 +5,7 @@ org.jooby modules - 1.5.1-SNAPSHOT + 1.6.9 4.0.0 diff --git a/modules/jooby-unbescape/README.md b/modules/jooby-unbescape/README.md index 373ab90695..5f8da4709b 100644 --- a/modules/jooby-unbescape/README.md +++ b/modules/jooby-unbescape/README.md @@ -1,5 +1,5 @@ -[![Maven Central](https://maven-badges.herokuapp.com/maven-central/org.jooby/jooby-unbescape/badge.svg)](https://maven-badges.herokuapp.com/maven-central/org.jooby/jooby-unbescape) -[![javadoc](https://javadoc.io/badge/org.jooby/jooby-unbescape.svg)](https://javadoc.io/doc/org.jooby/jooby-unbescape/1.5.0) +[![Maven](https://img.shields.io/maven-metadata/v/http/central.maven.org/maven2/org/jooby/jooby-unbescape/maven-metadata.xml.svg)](http://mvnrepository.com/artifact/org.jooby/jooby-unbescape/1.6.6) +[![javadoc](https://javadoc.io/badge/org.jooby/jooby-unbescape.svg)](https://javadoc.io/doc/org.jooby/jooby-unbescape/1.6.6) [![jooby-unbescape website](https://img.shields.io/badge/jooby-unbescape-brightgreen.svg)](http://jooby.org/doc/unbescape) # unbescape @@ -11,7 +11,7 @@ org.jooby jooby-unbescape - 1.5.0 + 1.6.6 ``` diff --git a/modules/jooby-unbescape/pom.xml b/modules/jooby-unbescape/pom.xml index 0f41cda346..d0037ceddd 100644 --- a/modules/jooby-unbescape/pom.xml +++ b/modules/jooby-unbescape/pom.xml @@ -5,7 +5,7 @@ org.jooby modules - 1.5.1-SNAPSHOT + 1.6.9 4.0.0 diff --git a/modules/jooby-undertow/README.md b/modules/jooby-undertow/README.md index ec3795a17b..4381490a61 100644 --- a/modules/jooby-undertow/README.md +++ b/modules/jooby-undertow/README.md @@ -1,5 +1,5 @@ -[![Maven Central](https://maven-badges.herokuapp.com/maven-central/org.jooby/jooby-undertow/badge.svg)](https://maven-badges.herokuapp.com/maven-central/org.jooby/jooby-undertow) -[![javadoc](https://javadoc.io/badge/org.jooby/jooby-undertow.svg)](https://javadoc.io/doc/org.jooby/jooby-undertow/1.5.0) +[![Maven](https://img.shields.io/maven-metadata/v/http/central.maven.org/maven2/org/jooby/jooby-undertow/maven-metadata.xml.svg)](http://mvnrepository.com/artifact/org.jooby/jooby-undertow/1.6.6) +[![javadoc](https://javadoc.io/badge/org.jooby/jooby-undertow.svg)](https://javadoc.io/doc/org.jooby/jooby-undertow/1.6.6) [![jooby-undertow website](https://img.shields.io/badge/jooby-undertow-brightgreen.svg)](http://jooby.org/doc/undertow) # undertow @@ -15,7 +15,7 @@ org.jooby jooby-undertow - 1.5.0 + 1.6.6 ``` diff --git a/modules/jooby-undertow/pom.xml b/modules/jooby-undertow/pom.xml index a421d91e80..adef4b78ce 100644 --- a/modules/jooby-undertow/pom.xml +++ b/modules/jooby-undertow/pom.xml @@ -5,7 +5,7 @@ org.jooby modules - 1.5.1-SNAPSHOT + 1.6.9 4.0.0 diff --git a/modules/jooby-undertow/src/main/java/org/jooby/internal/undertow/LogIoCallback.java b/modules/jooby-undertow/src/main/java/org/jooby/internal/undertow/LogIoCallback.java index 8e79a30792..a2d120aa41 100644 --- a/modules/jooby-undertow/src/main/java/org/jooby/internal/undertow/LogIoCallback.java +++ b/modules/jooby-undertow/src/main/java/org/jooby/internal/undertow/LogIoCallback.java @@ -204,7 +204,9 @@ package org.jooby.internal.undertow; import java.io.IOException; +import java.nio.channels.ClosedChannelException; +import org.jooby.internal.ConnectionResetByPeer; import org.jooby.spi.NativeResponse; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -232,7 +234,9 @@ public void onComplete(final HttpServerExchange exchange, final Sender sender) { @Override public void onException(final HttpServerExchange exchange, final Sender sender, final IOException x) { - log.error("execution of {} resulted in exception", exchange.getRequestPath(), x); + if (!(x instanceof ClosedChannelException)) { + log.error("execution of {} resulted in exception", exchange.getRequestPath(), x); + } callback.onException(exchange, sender, x); } diff --git a/modules/jooby-undertow/src/main/java/org/jooby/internal/undertow/UndertowRequest.java b/modules/jooby-undertow/src/main/java/org/jooby/internal/undertow/UndertowRequest.java index 86f4262131..0416c868db 100644 --- a/modules/jooby-undertow/src/main/java/org/jooby/internal/undertow/UndertowRequest.java +++ b/modules/jooby-undertow/src/main/java/org/jooby/internal/undertow/UndertowRequest.java @@ -208,14 +208,12 @@ import java.io.InputStream; import java.net.InetAddress; import java.net.URLDecoder; -import java.util.Collections; -import java.util.Deque; -import java.util.List; -import java.util.Optional; +import java.util.*; import java.util.concurrent.Executor; import java.util.stream.Collectors; +import java.util.stream.StreamSupport; -import io.undertow.server.handlers.form.FormDataParser; +import io.undertow.server.handlers.form.*; import org.jooby.Cookie; import org.jooby.MediaType; import org.jooby.Router; @@ -233,10 +231,7 @@ import io.undertow.server.BlockingHttpExchange; import io.undertow.server.HttpServerExchange; -import io.undertow.server.handlers.form.FormData; import io.undertow.server.handlers.form.FormData.FormValue; -import io.undertow.server.handlers.form.FormEncodedDataDefinition; -import io.undertow.server.handlers.form.MultiPartParserDefinition; import io.undertow.util.AttachmentKey; import io.undertow.util.HeaderValues; import io.undertow.util.HttpString; @@ -357,6 +352,21 @@ public List files(final String name) { return builder.build(); } + @Override + public List files() throws IOException { + FormData formData = parseForm(); + Iterator keyIterator = formData.iterator(); + Iterable iterableKeys = () -> keyIterator; + List retVal = StreamSupport.stream(iterableKeys.spliterator(), true) + .map(formData::get) + .filter(formValues -> formValues.peekFirst().isFileItem()) + .flatMap(Collection::stream) + .map(UndertowUpload::new) + .collect(Collectors.toList()); + + return Collections.unmodifiableList(retVal); + } + @Override public InputStream in() { blocking.get(); @@ -410,25 +420,22 @@ private FormData parseForm() { try { String tmpdir = conf.getString("application.tmpdir"); String charset = conf.getString("application.charset"); - String value = exchange.getRequestHeaders().getFirst("Content-Type"); - if (value != null) { - MediaType type = MediaType.valueOf(value); - if (MediaType.form.name().equals(type.name())) { - blocking.get(); - form = new FormEncodedDataDefinition() - .setDefaultEncoding(charset) - .create(exchange) - .parseBlocking(); - } else if (MediaType.multipart.name().equals(type.name())) { - blocking.get(); - form = new MultiPartParserDefinition() + + FormEncodedDataDefinition encodedParser = new FormEncodedDataDefinition().setDefaultEncoding(charset); + MultiPartParserDefinition multiPartParser = new MultiPartParserDefinition() .setTempFileLocation(new File(tmpdir).toPath()) - .setDefaultEncoding(charset) - .create(exchange) - .parseBlocking(); - } - } - } catch (IOException x) { + .setDefaultEncoding(charset); + blocking.get(); + FormDataParser parser = FormParserFactory + .builder(false) + .addParser(encodedParser) + .addParser(multiPartParser) + .build() + .createParser(exchange); + + form = parser != null ? parser.parseBlocking() : NO_FORM; + } catch (IOException iox) { + throw new IllegalArgumentException("Bad Request...", iox); } } return form; diff --git a/modules/jooby-undertow/src/main/java/org/jooby/internal/undertow/UndertowResponse.java b/modules/jooby-undertow/src/main/java/org/jooby/internal/undertow/UndertowResponse.java index 81ee01cbc1..7a1d60bf05 100644 --- a/modules/jooby-undertow/src/main/java/org/jooby/internal/undertow/UndertowResponse.java +++ b/modules/jooby-undertow/src/main/java/org/jooby/internal/undertow/UndertowResponse.java @@ -268,7 +268,8 @@ public void send(final byte[] bytes) throws Exception { @Override public void send(final ByteBuffer buffer) throws Exception { - exchange.getResponseSender().send(buffer); + endExchange = false; + exchange.getResponseSender().send(buffer, new LogIoCallback(IoCallback.END_EXCHANGE)); } @Override diff --git a/modules/jooby-whoops/README.md b/modules/jooby-whoops/README.md index 9f05af05ca..69ca0eef4a 100644 --- a/modules/jooby-whoops/README.md +++ b/modules/jooby-whoops/README.md @@ -1,5 +1,5 @@ -[![Maven Central](https://maven-badges.herokuapp.com/maven-central/org.jooby/jooby-whoops/badge.svg)](https://maven-badges.herokuapp.com/maven-central/org.jooby/jooby-whoops) -[![javadoc](https://javadoc.io/badge/org.jooby/jooby-whoops.svg)](https://javadoc.io/doc/org.jooby/jooby-whoops/1.5.0) +[![Maven](https://img.shields.io/maven-metadata/v/http/central.maven.org/maven2/org/jooby/jooby-whoops/maven-metadata.xml.svg)](http://mvnrepository.com/artifact/org.jooby/jooby-whoops/1.6.6) +[![javadoc](https://javadoc.io/badge/org.jooby/jooby-whoops.svg)](https://javadoc.io/doc/org.jooby/jooby-whoops/1.6.6) [![jooby-whoops website](https://img.shields.io/badge/jooby-whoops-brightgreen.svg)](http://jooby.org/doc/whoops) # whoops @@ -15,7 +15,7 @@ Pretty error page that helps you debug your web application. org.jooby jooby-whoops - 1.5.0 + 1.6.6 ``` diff --git a/modules/jooby-whoops/pom.xml b/modules/jooby-whoops/pom.xml index ee659ecb8b..94507ea4cf 100644 --- a/modules/jooby-whoops/pom.xml +++ b/modules/jooby-whoops/pom.xml @@ -5,7 +5,7 @@ org.jooby modules - 1.5.1-SNAPSHOT + 1.6.9 4.0.0 diff --git a/modules/jooby-yasson/README.md b/modules/jooby-yasson/README.md new file mode 100644 index 0000000000..41cc52faf4 --- /dev/null +++ b/modules/jooby-yasson/README.md @@ -0,0 +1,60 @@ +[![Maven](https://img.shields.io/maven-metadata/v/http/central.maven.org/maven2/org/jooby/jooby-yasson/maven-metadata.xml.svg)](http://mvnrepository.com/artifact/org.jooby/jooby-yasson/1.6.6) +[![javadoc](https://javadoc.io/badge/org.jooby/jooby-yasson.svg)](https://javadoc.io/doc/org.jooby/jooby-yasson/1.6.6) +[![jooby-yasson website](https://img.shields.io/badge/jooby-yasson-brightgreen.svg)](http://jooby.org/doc/yasson) +# yasson + +JSON support via [yasson](https://github.com/eclipse-ee4j/yasson) library. + +## exports + +* [json-b](http://json-b.net/users-guide.html) +* [Parser](/apidocs/org/jooby/Parser.html) +* [Renderer](/apidocs/org/jooby/Renderer.html) + +## dependency + +```xml + + org.jooby + jooby-yasson + 1.6.6 + +``` + +## usage + +```java +import org.jooby.json.Yasson; + +{ + use(new Yasson()); + + // sending + get("/my-api", req -> new MyObject()); + + // receiving a json body + post("/my-api", req -> { + MyObject obj = req.body(MyObject.class); + return obj; + }); + + // direct access to Jsonb + get("/access", req -> { + Jsonb jsonb = require(Jsonb.class); + // ... + }); +} +``` + +### configuration + +If you need a special setting or configuration for your [json-b](http://json-b.net/users-guide.html): + +```java +{ + use(new Yasson().doWith(builder -> { + builder.withFormatting(true); + // ... + }); +} +``` diff --git a/modules/jooby-yasson/pom.xml b/modules/jooby-yasson/pom.xml new file mode 100644 index 0000000000..4c3eafe522 --- /dev/null +++ b/modules/jooby-yasson/pom.xml @@ -0,0 +1,94 @@ + + + + + org.jooby + modules + 1.6.9 + + + 4.0.0 + jooby-yasson + + yasson module + + + + + + org.apache.maven.plugins + maven-surefire-plugin + + + **/*Test.java + **/*Feature.java + **/Issue*.java + + + + + + + + + + + org.jooby + jooby + ${project.version} + + + + + org.eclipse + yasson + + + + org.glassfish + javax.json + + + + + org.jooby + jooby + ${project.version} + test + tests + + + + junit + junit + test + + + + org.easymock + easymock + test + + + + org.powermock + powermock-api-easymock + test + + + + org.powermock + powermock-module-junit4 + test + + + + org.jacoco + org.jacoco.agent + runtime + test + + + + \ No newline at end of file diff --git a/modules/jooby-yasson/src/main/java/org/jooby/json/Yasson.java b/modules/jooby-yasson/src/main/java/org/jooby/json/Yasson.java new file mode 100644 index 0000000000..652df9c408 --- /dev/null +++ b/modules/jooby-yasson/src/main/java/org/jooby/json/Yasson.java @@ -0,0 +1,380 @@ +/** + * Apache License + * Version 2.0, January 2004 + * http://www.apache.org/licenses/ + * + * TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + * + * 1. Definitions. + * + * "License" shall mean the terms and conditions for use, reproduction, + * and distribution as defined by Sections 1 through 9 of this document. + * + * "Licensor" shall mean the copyright owner or entity authorized by + * the copyright owner that is granting the License. + * + * "Legal Entity" shall mean the union of the acting entity and all + * other entities that control, are controlled by, or are under common + * control with that entity. For the purposes of this definition, + * "control" means (i) the power, direct or indirect, to cause the + * direction or management of such entity, whether by contract or + * otherwise, or (ii) ownership of fifty percent (50%) or more of the + * outstanding shares, or (iii) beneficial ownership of such entity. + * + * "You" (or "Your") shall mean an individual or Legal Entity + * exercising permissions granted by this License. + * + * "Source" form shall mean the preferred form for making modifications, + * including but not limited to software source code, documentation + * source, and configuration files. + * + * "Object" form shall mean any form resulting from mechanical + * transformation or translation of a Source form, including but + * not limited to compiled object code, generated documentation, + * and conversions to other media types. + * + * "Work" shall mean the work of authorship, whether in Source or + * Object form, made available under the License, as indicated by a + * copyright notice that is included in or attached to the work + * (an example is provided in the Appendix below). + * + * "Derivative Works" shall mean any work, whether in Source or Object + * form, that is based on (or derived from) the Work and for which the + * editorial revisions, annotations, elaborations, or other modifications + * represent, as a whole, an original work of authorship. For the purposes + * of this License, Derivative Works shall not include works that remain + * separable from, or merely link (or bind by name) to the interfaces of, + * the Work and Derivative Works thereof. + * + * "Contribution" shall mean any work of authorship, including + * the original version of the Work and any modifications or additions + * to that Work or Derivative Works thereof, that is intentionally + * submitted to Licensor for inclusion in the Work by the copyright owner + * or by an individual or Legal Entity authorized to submit on behalf of + * the copyright owner. For the purposes of this definition, "submitted" + * means any form of electronic, verbal, or written communication sent + * to the Licensor or its representatives, including but not limited to + * communication on electronic mailing lists, source code control systems, + * and issue tracking systems that are managed by, or on behalf of, the + * Licensor for the purpose of discussing and improving the Work, but + * excluding communication that is conspicuously marked or otherwise + * designated in writing by the copyright owner as "Not a Contribution." + * + * "Contributor" shall mean Licensor and any individual or Legal Entity + * on behalf of whom a Contribution has been received by Licensor and + * subsequently incorporated within the Work. + * + * 2. Grant of Copyright License. Subject to the terms and conditions of + * this License, each Contributor hereby grants to You a perpetual, + * worldwide, non-exclusive, no-charge, royalty-free, irrevocable + * copyright license to reproduce, prepare Derivative Works of, + * publicly display, publicly perform, sublicense, and distribute the + * Work and such Derivative Works in Source or Object form. + * + * 3. Grant of Patent License. Subject to the terms and conditions of + * this License, each Contributor hereby grants to You a perpetual, + * worldwide, non-exclusive, no-charge, royalty-free, irrevocable + * (except as stated in this section) patent license to make, have made, + * use, offer to sell, sell, import, and otherwise transfer the Work, + * where such license applies only to those patent claims licensable + * by such Contributor that are necessarily infringed by their + * Contribution(s) alone or by combination of their Contribution(s) + * with the Work to which such Contribution(s) was submitted. If You + * institute patent litigation against any entity (including a + * cross-claim or counterclaim in a lawsuit) alleging that the Work + * or a Contribution incorporated within the Work constitutes direct + * or contributory patent infringement, then any patent licenses + * granted to You under this License for that Work shall terminate + * as of the date such litigation is filed. + * + * 4. Redistribution. You may reproduce and distribute copies of the + * Work or Derivative Works thereof in any medium, with or without + * modifications, and in Source or Object form, provided that You + * meet the following conditions: + * + * (a) You must give any other recipients of the Work or + * Derivative Works a copy of this License; and + * + * (b) You must cause any modified files to carry prominent notices + * stating that You changed the files; and + * + * (c) You must retain, in the Source form of any Derivative Works + * that You distribute, all copyright, patent, trademark, and + * attribution notices from the Source form of the Work, + * excluding those notices that do not pertain to any part of + * the Derivative Works; and + * + * (d) If the Work includes a "NOTICE" text file as part of its + * distribution, then any Derivative Works that You distribute must + * include a readable copy of the attribution notices contained + * within such NOTICE file, excluding those notices that do not + * pertain to any part of the Derivative Works, in at least one + * of the following places: within a NOTICE text file distributed + * as part of the Derivative Works; within the Source form or + * documentation, if provided along with the Derivative Works; or, + * within a display generated by the Derivative Works, if and + * wherever such third-party notices normally appear. The contents + * of the NOTICE file are for informational purposes only and + * do not modify the License. You may add Your own attribution + * notices within Derivative Works that You distribute, alongside + * or as an addendum to the NOTICE text from the Work, provided + * that such additional attribution notices cannot be construed + * as modifying the License. + * + * You may add Your own copyright statement to Your modifications and + * may provide additional or different license terms and conditions + * for use, reproduction, or distribution of Your modifications, or + * for any such Derivative Works as a whole, provided Your use, + * reproduction, and distribution of the Work otherwise complies with + * the conditions stated in this License. + * + * 5. Submission of Contributions. Unless You explicitly state otherwise, + * any Contribution intentionally submitted for inclusion in the Work + * by You to the Licensor shall be under the terms and conditions of + * this License, without any additional terms or conditions. + * Notwithstanding the above, nothing herein shall supersede or modify + * the terms of any separate license agreement you may have executed + * with Licensor regarding such Contributions. + * + * 6. Trademarks. This License does not grant permission to use the trade + * names, trademarks, service marks, or product names of the Licensor, + * except as required for reasonable and customary use in describing the + * origin of the Work and reproducing the content of the NOTICE file. + * + * 7. Disclaimer of Warranty. Unless required by applicable law or + * agreed to in writing, Licensor provides the Work (and each + * Contributor provides its Contributions) on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied, including, without limitation, any warranties or conditions + * of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + * PARTICULAR PURPOSE. You are solely responsible for determining the + * appropriateness of using or redistributing the Work and assume any + * risks associated with Your exercise of permissions under this License. + * + * 8. Limitation of Liability. In no event and under no legal theory, + * whether in tort (including negligence), contract, or otherwise, + * unless required by applicable law (such as deliberate and grossly + * negligent acts) or agreed to in writing, shall any Contributor be + * liable to You for damages, including any direct, indirect, special, + * incidental, or consequential damages of any character arising as a + * result of this License or out of the use or inability to use the + * Work (including but not limited to damages for loss of goodwill, + * work stoppage, computer failure or malfunction, or any and all + * other commercial damages or losses), even if such Contributor + * has been advised of the possibility of such damages. + * + * 9. Accepting Warranty or Additional Liability. While redistributing + * the Work or Derivative Works thereof, You may choose to offer, + * and charge a fee for, acceptance of support, warranty, indemnity, + * or other liability obligations and/or rights consistent with this + * License. However, in accepting such obligations, You may act only + * on Your own behalf and on Your sole responsibility, not on behalf + * of any other Contributor, and only if You agree to indemnify, + * defend, and hold each Contributor harmless for any liability + * incurred by, or claims asserted against, such Contributor by reason + * of your accepting any such warranty or additional liability. + * + * END OF TERMS AND CONDITIONS + * + * APPENDIX: How to apply the Apache License to your work. + * + * To apply the Apache License to your work, attach the following + * boilerplate notice, with the fields enclosed by brackets "{}" + * replaced with your own identifying information. (Don't include + * the brackets!) The text should be enclosed in the appropriate + * comment syntax for the file format. We also recommend that a + * file or class name and description of purpose be included on the + * same "printed page" as the copyright notice for easier + * identification within third-party archives. + * + * Copyright 2014 Edgar Espina + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jooby.json; + +import static java.util.Objects.requireNonNull; + +import java.util.function.BiConsumer; +import java.util.function.Consumer; + +import javax.json.Json; +import javax.json.bind.Jsonb; +import javax.json.bind.JsonbBuilder; +import javax.json.bind.JsonbConfig; + +import org.jooby.Env; +import org.jooby.Jooby; +import org.jooby.MediaType; +import org.jooby.Parser; +import org.jooby.Renderer; + +import com.google.inject.Binder; +import com.google.inject.multibindings.Multibinder; +import com.typesafe.config.Config; + +/** + * JSON support via Yasson library. + * + *

exposes

+ * + *
    + *
  • A {@link Jsonb}
  • + *
  • A {@link Parser}
  • + *
  • A {@link Renderer}
  • + *
+ * + *

usage

+ * + *
+ * {
+ *   use(new Yasson());
+ *
+ *   // sending
+ *   get("/my-api", req {@literal ->} new MyObject());
+ *
+ *   // receiving a json body
+ *   post("/my-api", req {@literal ->} {
+ *     MyObject obj = req.body(MyObject.class);
+ *     return obj;
+ *   });
+ *
+ *   // direct access to Jsonb
+ *   get("/access", req {@literal ->} {
+ *     Jsonb jsonb = req.require(Jsonb.class);
+ *     // ...
+ *   });
+ * }
+ * 
+ * + *

configuration

+ * + *

+ * If you need a special setting or configuration for your {@link Jsonb}: + *

+ * + *
+ * {
+ *   use(new Yasson().doWith(builder {@literal ->} {
+ *     builder.withFormatting(true);
+ *     // ...
+ *   });
+ * }
+ * 
+ * + * @author Daniel Dias + * @since 1.6.0 + */ +public class Yasson implements Jooby.Module { + + private final MediaType type; + + private BiConsumer configurer; + + private boolean raw; + + /** + * Creates a new {@link Jsonb}. + * + * @param type {@link MediaType} to use. + */ + public Yasson(final MediaType type) { + this.type = requireNonNull(type, "Media type is required."); + } + + /** + * Creates a new {@link Jsonb} and set type to: {@link MediaType#json}. + * + */ + public Yasson() { + this(MediaType.json); + } + + /** + * Configurer callback. + * + *
+   * {
+   *   use(new Yasson().doWith(builder {@literal ->} {
+   *     builder.withFormatting(true);
+   *     // ...
+   *   });
+   * }
+   * 
+ * + * @param configurer A callback. + * @return This instance. + */ + public Yasson doWith(final BiConsumer configurer) { + this.configurer = requireNonNull(configurer, "Configurer callback is required."); + return this; + } + + /** + * Configurer callback. + * + *
+   * {
+   *   use(new Yasson().doWith((builder, config) {@literal ->} {
+   *     builder.withFormatting(true);
+   *     // ...
+   *   });
+   * }
+   * 
+ * + * @param configurer A callback. + * @return This instance. + */ + public Yasson doWith(final Consumer configurer) { + requireNonNull(configurer, "Configurer callback is required."); + this.configurer = (jsonConfig, conf) -> configurer.accept(jsonConfig); + return this; + } + + @Override + public void configure(final Env env, final Config config, final Binder binder) { + JsonbConfig jsonbConfig = new JsonbConfig(); + + if (configurer != null) { + configurer.accept(jsonbConfig, config); + } + + Jsonb jsonb = JsonbBuilder.create(jsonbConfig); + + binder.bind(Jsonb.class).toInstance(jsonb); + + Multibinder.newSetBinder(binder, Parser.class).addBinding().toInstance(new YassonParser(type, jsonb)); + + YassonRenderer renderer = raw ? new YassonRawRenderer(type, jsonb) : new YassonRenderer(type, jsonb); + + Multibinder.newSetBinder(binder, Renderer.class).addBinding().toInstance(renderer); + } + + /** + * Add support raw string json responses: + * + *
{@code
+   * {
+   *   get("/raw", () -> {
+   *     return "{\"raw\": \"json\"}";
+   *   });
+   * }
+   * }
+ * + * @return This module. + */ + public Yasson raw() { + raw = true; + return this; + } +} \ No newline at end of file diff --git a/modules/jooby-yasson/src/main/java/org/jooby/json/YassonParser.java b/modules/jooby-yasson/src/main/java/org/jooby/json/YassonParser.java new file mode 100644 index 0000000000..4113412e9b --- /dev/null +++ b/modules/jooby-yasson/src/main/java/org/jooby/json/YassonParser.java @@ -0,0 +1,249 @@ +/** + * Apache License + * Version 2.0, January 2004 + * http://www.apache.org/licenses/ + * + * TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + * + * 1. Definitions. + * + * "License" shall mean the terms and conditions for use, reproduction, + * and distribution as defined by Sections 1 through 9 of this document. + * + * "Licensor" shall mean the copyright owner or entity authorized by + * the copyright owner that is granting the License. + * + * "Legal Entity" shall mean the union of the acting entity and all + * other entities that control, are controlled by, or are under common + * control with that entity. For the purposes of this definition, + * "control" means (i) the power, direct or indirect, to cause the + * direction or management of such entity, whether by contract or + * otherwise, or (ii) ownership of fifty percent (50%) or more of the + * outstanding shares, or (iii) beneficial ownership of such entity. + * + * "You" (or "Your") shall mean an individual or Legal Entity + * exercising permissions granted by this License. + * + * "Source" form shall mean the preferred form for making modifications, + * including but not limited to software source code, documentation + * source, and configuration files. + * + * "Object" form shall mean any form resulting from mechanical + * transformation or translation of a Source form, including but + * not limited to compiled object code, generated documentation, + * and conversions to other media types. + * + * "Work" shall mean the work of authorship, whether in Source or + * Object form, made available under the License, as indicated by a + * copyright notice that is included in or attached to the work + * (an example is provided in the Appendix below). + * + * "Derivative Works" shall mean any work, whether in Source or Object + * form, that is based on (or derived from) the Work and for which the + * editorial revisions, annotations, elaborations, or other modifications + * represent, as a whole, an original work of authorship. For the purposes + * of this License, Derivative Works shall not include works that remain + * separable from, or merely link (or bind by name) to the interfaces of, + * the Work and Derivative Works thereof. + * + * "Contribution" shall mean any work of authorship, including + * the original version of the Work and any modifications or additions + * to that Work or Derivative Works thereof, that is intentionally + * submitted to Licensor for inclusion in the Work by the copyright owner + * or by an individual or Legal Entity authorized to submit on behalf of + * the copyright owner. For the purposes of this definition, "submitted" + * means any form of electronic, verbal, or written communication sent + * to the Licensor or its representatives, including but not limited to + * communication on electronic mailing lists, source code control systems, + * and issue tracking systems that are managed by, or on behalf of, the + * Licensor for the purpose of discussing and improving the Work, but + * excluding communication that is conspicuously marked or otherwise + * designated in writing by the copyright owner as "Not a Contribution." + * + * "Contributor" shall mean Licensor and any individual or Legal Entity + * on behalf of whom a Contribution has been received by Licensor and + * subsequently incorporated within the Work. + * + * 2. Grant of Copyright License. Subject to the terms and conditions of + * this License, each Contributor hereby grants to You a perpetual, + * worldwide, non-exclusive, no-charge, royalty-free, irrevocable + * copyright license to reproduce, prepare Derivative Works of, + * publicly display, publicly perform, sublicense, and distribute the + * Work and such Derivative Works in Source or Object form. + * + * 3. Grant of Patent License. Subject to the terms and conditions of + * this License, each Contributor hereby grants to You a perpetual, + * worldwide, non-exclusive, no-charge, royalty-free, irrevocable + * (except as stated in this section) patent license to make, have made, + * use, offer to sell, sell, import, and otherwise transfer the Work, + * where such license applies only to those patent claims licensable + * by such Contributor that are necessarily infringed by their + * Contribution(s) alone or by combination of their Contribution(s) + * with the Work to which such Contribution(s) was submitted. If You + * institute patent litigation against any entity (including a + * cross-claim or counterclaim in a lawsuit) alleging that the Work + * or a Contribution incorporated within the Work constitutes direct + * or contributory patent infringement, then any patent licenses + * granted to You under this License for that Work shall terminate + * as of the date such litigation is filed. + * + * 4. Redistribution. You may reproduce and distribute copies of the + * Work or Derivative Works thereof in any medium, with or without + * modifications, and in Source or Object form, provided that You + * meet the following conditions: + * + * (a) You must give any other recipients of the Work or + * Derivative Works a copy of this License; and + * + * (b) You must cause any modified files to carry prominent notices + * stating that You changed the files; and + * + * (c) You must retain, in the Source form of any Derivative Works + * that You distribute, all copyright, patent, trademark, and + * attribution notices from the Source form of the Work, + * excluding those notices that do not pertain to any part of + * the Derivative Works; and + * + * (d) If the Work includes a "NOTICE" text file as part of its + * distribution, then any Derivative Works that You distribute must + * include a readable copy of the attribution notices contained + * within such NOTICE file, excluding those notices that do not + * pertain to any part of the Derivative Works, in at least one + * of the following places: within a NOTICE text file distributed + * as part of the Derivative Works; within the Source form or + * documentation, if provided along with the Derivative Works; or, + * within a display generated by the Derivative Works, if and + * wherever such third-party notices normally appear. The contents + * of the NOTICE file are for informational purposes only and + * do not modify the License. You may add Your own attribution + * notices within Derivative Works that You distribute, alongside + * or as an addendum to the NOTICE text from the Work, provided + * that such additional attribution notices cannot be construed + * as modifying the License. + * + * You may add Your own copyright statement to Your modifications and + * may provide additional or different license terms and conditions + * for use, reproduction, or distribution of Your modifications, or + * for any such Derivative Works as a whole, provided Your use, + * reproduction, and distribution of the Work otherwise complies with + * the conditions stated in this License. + * + * 5. Submission of Contributions. Unless You explicitly state otherwise, + * any Contribution intentionally submitted for inclusion in the Work + * by You to the Licensor shall be under the terms and conditions of + * this License, without any additional terms or conditions. + * Notwithstanding the above, nothing herein shall supersede or modify + * the terms of any separate license agreement you may have executed + * with Licensor regarding such Contributions. + * + * 6. Trademarks. This License does not grant permission to use the trade + * names, trademarks, service marks, or product names of the Licensor, + * except as required for reasonable and customary use in describing the + * origin of the Work and reproducing the content of the NOTICE file. + * + * 7. Disclaimer of Warranty. Unless required by applicable law or + * agreed to in writing, Licensor provides the Work (and each + * Contributor provides its Contributions) on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied, including, without limitation, any warranties or conditions + * of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + * PARTICULAR PURPOSE. You are solely responsible for determining the + * appropriateness of using or redistributing the Work and assume any + * risks associated with Your exercise of permissions under this License. + * + * 8. Limitation of Liability. In no event and under no legal theory, + * whether in tort (including negligence), contract, or otherwise, + * unless required by applicable law (such as deliberate and grossly + * negligent acts) or agreed to in writing, shall any Contributor be + * liable to You for damages, including any direct, indirect, special, + * incidental, or consequential damages of any character arising as a + * result of this License or out of the use or inability to use the + * Work (including but not limited to damages for loss of goodwill, + * work stoppage, computer failure or malfunction, or any and all + * other commercial damages or losses), even if such Contributor + * has been advised of the possibility of such damages. + * + * 9. Accepting Warranty or Additional Liability. While redistributing + * the Work or Derivative Works thereof, You may choose to offer, + * and charge a fee for, acceptance of support, warranty, indemnity, + * or other liability obligations and/or rights consistent with this + * License. However, in accepting such obligations, You may act only + * on Your own behalf and on Your sole responsibility, not on behalf + * of any other Contributor, and only if You agree to indemnify, + * defend, and hold each Contributor harmless for any liability + * incurred by, or claims asserted against, such Contributor by reason + * of your accepting any such warranty or additional liability. + * + * END OF TERMS AND CONDITIONS + * + * APPENDIX: How to apply the Apache License to your work. + * + * To apply the Apache License to your work, attach the following + * boilerplate notice, with the fields enclosed by brackets "{}" + * replaced with your own identifying information. (Don't include + * the brackets!) The text should be enclosed in the appropriate + * comment syntax for the file format. We also recommend that a + * file or class name and description of purpose be included on the + * same "printed page" as the copyright notice for easier + * identification within third-party archives. + * + * Copyright 2014 Edgar Espina + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jooby.json; + +import static java.util.Objects.requireNonNull; +import javax.json.bind.Jsonb; + +import org.jooby.MediaType; +import org.jooby.Parser; +import org.jooby.Parser.Context; + +import com.google.inject.TypeLiteral; + + /** + * @author Daniel Dias + * @since 1.6.0 + */ +class YassonParser implements Parser { + + private final MediaType type; + + private final Jsonb jsonb; + + public YassonParser(final MediaType type, final Jsonb jsonb) { + this.type = requireNonNull(type, "Media type is required."); + this.jsonb = requireNonNull(jsonb, "Jsonb is required."); + } + + @Override + public Object parse(final TypeLiteral type, final Context ctx) throws Throwable { + MediaType ctype = ctx.type(); + if (ctype.isAny()) { + return ctx.next(); + } + + if (ctype.matches(this.type)) { + return ctx + .ifbody(body -> jsonb.fromJson(body.text(), type.getType())) + .ifparam(values -> jsonb.fromJson(values.first(), type.getType())); + } + return ctx.next(); + } + + @Override + public String toString() { + return "yasson"; + } +} \ No newline at end of file diff --git a/modules/jooby-yasson/src/main/java/org/jooby/json/YassonRawRenderer.java b/modules/jooby-yasson/src/main/java/org/jooby/json/YassonRawRenderer.java new file mode 100644 index 0000000000..47169063b6 --- /dev/null +++ b/modules/jooby-yasson/src/main/java/org/jooby/json/YassonRawRenderer.java @@ -0,0 +1,229 @@ +/** + * Apache License + * Version 2.0, January 2004 + * http://www.apache.org/licenses/ + * + * TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + * + * 1. Definitions. + * + * "License" shall mean the terms and conditions for use, reproduction, + * and distribution as defined by Sections 1 through 9 of this document. + * + * "Licensor" shall mean the copyright owner or entity authorized by + * the copyright owner that is granting the License. + * + * "Legal Entity" shall mean the union of the acting entity and all + * other entities that control, are controlled by, or are under common + * control with that entity. For the purposes of this definition, + * "control" means (i) the power, direct or indirect, to cause the + * direction or management of such entity, whether by contract or + * otherwise, or (ii) ownership of fifty percent (50%) or more of the + * outstanding shares, or (iii) beneficial ownership of such entity. + * + * "You" (or "Your") shall mean an individual or Legal Entity + * exercising permissions granted by this License. + * + * "Source" form shall mean the preferred form for making modifications, + * including but not limited to software source code, documentation + * source, and configuration files. + * + * "Object" form shall mean any form resulting from mechanical + * transformation or translation of a Source form, including but + * not limited to compiled object code, generated documentation, + * and conversions to other media types. + * + * "Work" shall mean the work of authorship, whether in Source or + * Object form, made available under the License, as indicated by a + * copyright notice that is included in or attached to the work + * (an example is provided in the Appendix below). + * + * "Derivative Works" shall mean any work, whether in Source or Object + * form, that is based on (or derived from) the Work and for which the + * editorial revisions, annotations, elaborations, or other modifications + * represent, as a whole, an original work of authorship. For the purposes + * of this License, Derivative Works shall not include works that remain + * separable from, or merely link (or bind by name) to the interfaces of, + * the Work and Derivative Works thereof. + * + * "Contribution" shall mean any work of authorship, including + * the original version of the Work and any modifications or additions + * to that Work or Derivative Works thereof, that is intentionally + * submitted to Licensor for inclusion in the Work by the copyright owner + * or by an individual or Legal Entity authorized to submit on behalf of + * the copyright owner. For the purposes of this definition, "submitted" + * means any form of electronic, verbal, or written communication sent + * to the Licensor or its representatives, including but not limited to + * communication on electronic mailing lists, source code control systems, + * and issue tracking systems that are managed by, or on behalf of, the + * Licensor for the purpose of discussing and improving the Work, but + * excluding communication that is conspicuously marked or otherwise + * designated in writing by the copyright owner as "Not a Contribution." + * + * "Contributor" shall mean Licensor and any individual or Legal Entity + * on behalf of whom a Contribution has been received by Licensor and + * subsequently incorporated within the Work. + * + * 2. Grant of Copyright License. Subject to the terms and conditions of + * this License, each Contributor hereby grants to You a perpetual, + * worldwide, non-exclusive, no-charge, royalty-free, irrevocable + * copyright license to reproduce, prepare Derivative Works of, + * publicly display, publicly perform, sublicense, and distribute the + * Work and such Derivative Works in Source or Object form. + * + * 3. Grant of Patent License. Subject to the terms and conditions of + * this License, each Contributor hereby grants to You a perpetual, + * worldwide, non-exclusive, no-charge, royalty-free, irrevocable + * (except as stated in this section) patent license to make, have made, + * use, offer to sell, sell, import, and otherwise transfer the Work, + * where such license applies only to those patent claims licensable + * by such Contributor that are necessarily infringed by their + * Contribution(s) alone or by combination of their Contribution(s) + * with the Work to which such Contribution(s) was submitted. If You + * institute patent litigation against any entity (including a + * cross-claim or counterclaim in a lawsuit) alleging that the Work + * or a Contribution incorporated within the Work constitutes direct + * or contributory patent infringement, then any patent licenses + * granted to You under this License for that Work shall terminate + * as of the date such litigation is filed. + * + * 4. Redistribution. You may reproduce and distribute copies of the + * Work or Derivative Works thereof in any medium, with or without + * modifications, and in Source or Object form, provided that You + * meet the following conditions: + * + * (a) You must give any other recipients of the Work or + * Derivative Works a copy of this License; and + * + * (b) You must cause any modified files to carry prominent notices + * stating that You changed the files; and + * + * (c) You must retain, in the Source form of any Derivative Works + * that You distribute, all copyright, patent, trademark, and + * attribution notices from the Source form of the Work, + * excluding those notices that do not pertain to any part of + * the Derivative Works; and + * + * (d) If the Work includes a "NOTICE" text file as part of its + * distribution, then any Derivative Works that You distribute must + * include a readable copy of the attribution notices contained + * within such NOTICE file, excluding those notices that do not + * pertain to any part of the Derivative Works, in at least one + * of the following places: within a NOTICE text file distributed + * as part of the Derivative Works; within the Source form or + * documentation, if provided along with the Derivative Works; or, + * within a display generated by the Derivative Works, if and + * wherever such third-party notices normally appear. The contents + * of the NOTICE file are for informational purposes only and + * do not modify the License. You may add Your own attribution + * notices within Derivative Works that You distribute, alongside + * or as an addendum to the NOTICE text from the Work, provided + * that such additional attribution notices cannot be construed + * as modifying the License. + * + * You may add Your own copyright statement to Your modifications and + * may provide additional or different license terms and conditions + * for use, reproduction, or distribution of Your modifications, or + * for any such Derivative Works as a whole, provided Your use, + * reproduction, and distribution of the Work otherwise complies with + * the conditions stated in this License. + * + * 5. Submission of Contributions. Unless You explicitly state otherwise, + * any Contribution intentionally submitted for inclusion in the Work + * by You to the Licensor shall be under the terms and conditions of + * this License, without any additional terms or conditions. + * Notwithstanding the above, nothing herein shall supersede or modify + * the terms of any separate license agreement you may have executed + * with Licensor regarding such Contributions. + * + * 6. Trademarks. This License does not grant permission to use the trade + * names, trademarks, service marks, or product names of the Licensor, + * except as required for reasonable and customary use in describing the + * origin of the Work and reproducing the content of the NOTICE file. + * + * 7. Disclaimer of Warranty. Unless required by applicable law or + * agreed to in writing, Licensor provides the Work (and each + * Contributor provides its Contributions) on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied, including, without limitation, any warranties or conditions + * of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + * PARTICULAR PURPOSE. You are solely responsible for determining the + * appropriateness of using or redistributing the Work and assume any + * risks associated with Your exercise of permissions under this License. + * + * 8. Limitation of Liability. In no event and under no legal theory, + * whether in tort (including negligence), contract, or otherwise, + * unless required by applicable law (such as deliberate and grossly + * negligent acts) or agreed to in writing, shall any Contributor be + * liable to You for damages, including any direct, indirect, special, + * incidental, or consequential damages of any character arising as a + * result of this License or out of the use or inability to use the + * Work (including but not limited to damages for loss of goodwill, + * work stoppage, computer failure or malfunction, or any and all + * other commercial damages or losses), even if such Contributor + * has been advised of the possibility of such damages. + * + * 9. Accepting Warranty or Additional Liability. While redistributing + * the Work or Derivative Works thereof, You may choose to offer, + * and charge a fee for, acceptance of support, warranty, indemnity, + * or other liability obligations and/or rights consistent with this + * License. However, in accepting such obligations, You may act only + * on Your own behalf and on Your sole responsibility, not on behalf + * of any other Contributor, and only if You agree to indemnify, + * defend, and hold each Contributor harmless for any liability + * incurred by, or claims asserted against, such Contributor by reason + * of your accepting any such warranty or additional liability. + * + * END OF TERMS AND CONDITIONS + * + * APPENDIX: How to apply the Apache License to your work. + * + * To apply the Apache License to your work, attach the following + * boilerplate notice, with the fields enclosed by brackets "{}" + * replaced with your own identifying information. (Don't include + * the brackets!) The text should be enclosed in the appropriate + * comment syntax for the file format. We also recommend that a + * file or class name and description of purpose be included on the + * same "printed page" as the copyright notice for easier + * identification within third-party archives. + * + * Copyright 2014 Edgar Espina + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jooby.json; + +import javax.json.bind.Jsonb; + +import org.jooby.MediaType; + +/** + * @author Daniel Dias + * @since 1.6.0 + */ +public class YassonRawRenderer extends YassonRenderer { + + public YassonRawRenderer(MediaType type, Jsonb jsonb) { + super(type, jsonb); + } + + @Override + public void render(Object value, Context ctx) throws Exception { + if (value instanceof CharSequence) { + ctx.type(type).send(value.toString()); + } else { + super.render(value, ctx); + } + } +} \ No newline at end of file diff --git a/modules/jooby-yasson/src/main/java/org/jooby/json/YassonRenderer.java b/modules/jooby-yasson/src/main/java/org/jooby/json/YassonRenderer.java new file mode 100644 index 0000000000..7fcebdc205 --- /dev/null +++ b/modules/jooby-yasson/src/main/java/org/jooby/json/YassonRenderer.java @@ -0,0 +1,245 @@ +/** + * Apache License + * Version 2.0, January 2004 + * http://www.apache.org/licenses/ + * + * TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + * + * 1. Definitions. + * + * "License" shall mean the terms and conditions for use, reproduction, + * and distribution as defined by Sections 1 through 9 of this document. + * + * "Licensor" shall mean the copyright owner or entity authorized by + * the copyright owner that is granting the License. + * + * "Legal Entity" shall mean the union of the acting entity and all + * other entities that control, are controlled by, or are under common + * control with that entity. For the purposes of this definition, + * "control" means (i) the power, direct or indirect, to cause the + * direction or management of such entity, whether by contract or + * otherwise, or (ii) ownership of fifty percent (50%) or more of the + * outstanding shares, or (iii) beneficial ownership of such entity. + * + * "You" (or "Your") shall mean an individual or Legal Entity + * exercising permissions granted by this License. + * + * "Source" form shall mean the preferred form for making modifications, + * including but not limited to software source code, documentation + * source, and configuration files. + * + * "Object" form shall mean any form resulting from mechanical + * transformation or translation of a Source form, including but + * not limited to compiled object code, generated documentation, + * and conversions to other media types. + * + * "Work" shall mean the work of authorship, whether in Source or + * Object form, made available under the License, as indicated by a + * copyright notice that is included in or attached to the work + * (an example is provided in the Appendix below). + * + * "Derivative Works" shall mean any work, whether in Source or Object + * form, that is based on (or derived from) the Work and for which the + * editorial revisions, annotations, elaborations, or other modifications + * represent, as a whole, an original work of authorship. For the purposes + * of this License, Derivative Works shall not include works that remain + * separable from, or merely link (or bind by name) to the interfaces of, + * the Work and Derivative Works thereof. + * + * "Contribution" shall mean any work of authorship, including + * the original version of the Work and any modifications or additions + * to that Work or Derivative Works thereof, that is intentionally + * submitted to Licensor for inclusion in the Work by the copyright owner + * or by an individual or Legal Entity authorized to submit on behalf of + * the copyright owner. For the purposes of this definition, "submitted" + * means any form of electronic, verbal, or written communication sent + * to the Licensor or its representatives, including but not limited to + * communication on electronic mailing lists, source code control systems, + * and issue tracking systems that are managed by, or on behalf of, the + * Licensor for the purpose of discussing and improving the Work, but + * excluding communication that is conspicuously marked or otherwise + * designated in writing by the copyright owner as "Not a Contribution." + * + * "Contributor" shall mean Licensor and any individual or Legal Entity + * on behalf of whom a Contribution has been received by Licensor and + * subsequently incorporated within the Work. + * + * 2. Grant of Copyright License. Subject to the terms and conditions of + * this License, each Contributor hereby grants to You a perpetual, + * worldwide, non-exclusive, no-charge, royalty-free, irrevocable + * copyright license to reproduce, prepare Derivative Works of, + * publicly display, publicly perform, sublicense, and distribute the + * Work and such Derivative Works in Source or Object form. + * + * 3. Grant of Patent License. Subject to the terms and conditions of + * this License, each Contributor hereby grants to You a perpetual, + * worldwide, non-exclusive, no-charge, royalty-free, irrevocable + * (except as stated in this section) patent license to make, have made, + * use, offer to sell, sell, import, and otherwise transfer the Work, + * where such license applies only to those patent claims licensable + * by such Contributor that are necessarily infringed by their + * Contribution(s) alone or by combination of their Contribution(s) + * with the Work to which such Contribution(s) was submitted. If You + * institute patent litigation against any entity (including a + * cross-claim or counterclaim in a lawsuit) alleging that the Work + * or a Contribution incorporated within the Work constitutes direct + * or contributory patent infringement, then any patent licenses + * granted to You under this License for that Work shall terminate + * as of the date such litigation is filed. + * + * 4. Redistribution. You may reproduce and distribute copies of the + * Work or Derivative Works thereof in any medium, with or without + * modifications, and in Source or Object form, provided that You + * meet the following conditions: + * + * (a) You must give any other recipients of the Work or + * Derivative Works a copy of this License; and + * + * (b) You must cause any modified files to carry prominent notices + * stating that You changed the files; and + * + * (c) You must retain, in the Source form of any Derivative Works + * that You distribute, all copyright, patent, trademark, and + * attribution notices from the Source form of the Work, + * excluding those notices that do not pertain to any part of + * the Derivative Works; and + * + * (d) If the Work includes a "NOTICE" text file as part of its + * distribution, then any Derivative Works that You distribute must + * include a readable copy of the attribution notices contained + * within such NOTICE file, excluding those notices that do not + * pertain to any part of the Derivative Works, in at least one + * of the following places: within a NOTICE text file distributed + * as part of the Derivative Works; within the Source form or + * documentation, if provided along with the Derivative Works; or, + * within a display generated by the Derivative Works, if and + * wherever such third-party notices normally appear. The contents + * of the NOTICE file are for informational purposes only and + * do not modify the License. You may add Your own attribution + * notices within Derivative Works that You distribute, alongside + * or as an addendum to the NOTICE text from the Work, provided + * that such additional attribution notices cannot be construed + * as modifying the License. + * + * You may add Your own copyright statement to Your modifications and + * may provide additional or different license terms and conditions + * for use, reproduction, or distribution of Your modifications, or + * for any such Derivative Works as a whole, provided Your use, + * reproduction, and distribution of the Work otherwise complies with + * the conditions stated in this License. + * + * 5. Submission of Contributions. Unless You explicitly state otherwise, + * any Contribution intentionally submitted for inclusion in the Work + * by You to the Licensor shall be under the terms and conditions of + * this License, without any additional terms or conditions. + * Notwithstanding the above, nothing herein shall supersede or modify + * the terms of any separate license agreement you may have executed + * with Licensor regarding such Contributions. + * + * 6. Trademarks. This License does not grant permission to use the trade + * names, trademarks, service marks, or product names of the Licensor, + * except as required for reasonable and customary use in describing the + * origin of the Work and reproducing the content of the NOTICE file. + * + * 7. Disclaimer of Warranty. Unless required by applicable law or + * agreed to in writing, Licensor provides the Work (and each + * Contributor provides its Contributions) on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied, including, without limitation, any warranties or conditions + * of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + * PARTICULAR PURPOSE. You are solely responsible for determining the + * appropriateness of using or redistributing the Work and assume any + * risks associated with Your exercise of permissions under this License. + * + * 8. Limitation of Liability. In no event and under no legal theory, + * whether in tort (including negligence), contract, or otherwise, + * unless required by applicable law (such as deliberate and grossly + * negligent acts) or agreed to in writing, shall any Contributor be + * liable to You for damages, including any direct, indirect, special, + * incidental, or consequential damages of any character arising as a + * result of this License or out of the use or inability to use the + * Work (including but not limited to damages for loss of goodwill, + * work stoppage, computer failure or malfunction, or any and all + * other commercial damages or losses), even if such Contributor + * has been advised of the possibility of such damages. + * + * 9. Accepting Warranty or Additional Liability. While redistributing + * the Work or Derivative Works thereof, You may choose to offer, + * and charge a fee for, acceptance of support, warranty, indemnity, + * or other liability obligations and/or rights consistent with this + * License. However, in accepting such obligations, You may act only + * on Your own behalf and on Your sole responsibility, not on behalf + * of any other Contributor, and only if You agree to indemnify, + * defend, and hold each Contributor harmless for any liability + * incurred by, or claims asserted against, such Contributor by reason + * of your accepting any such warranty or additional liability. + * + * END OF TERMS AND CONDITIONS + * + * APPENDIX: How to apply the Apache License to your work. + * + * To apply the Apache License to your work, attach the following + * boilerplate notice, with the fields enclosed by brackets "{}" + * replaced with your own identifying information. (Don't include + * the brackets!) The text should be enclosed in the appropriate + * comment syntax for the file format. We also recommend that a + * file or class name and description of purpose be included on the + * same "printed page" as the copyright notice for easier + * identification within third-party archives. + * + * Copyright 2014 Edgar Espina + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jooby.json; + +import static java.util.Objects.requireNonNull; + +import javax.json.bind.Jsonb; + +import org.jooby.MediaType; +import org.jooby.Renderer; + + /** + * @author Daniel Dias + * @since 1.6.0 + */ +public class YassonRenderer implements Renderer { + + protected final MediaType type; + + private final Jsonb jsonb; + + public YassonRenderer(final MediaType type, final Jsonb jsonb) { + this.type = requireNonNull(type, "Media type is required."); + + this.jsonb = requireNonNull(jsonb, "Jsonb is required."); + } + + @Override + public void render(final Object object, final Context ctx) throws Exception { + if (ctx.accepts(this.type)) { + ctx.type(this.type).send(jsonb.toJson(object)); + } + } + + @Override + public String name() { + return "json"; + } + + @Override + public String toString() { + return name(); + } +} \ No newline at end of file diff --git a/modules/jooby-yasson/src/test/java/org/jooby/json/YassonParserTest.java b/modules/jooby-yasson/src/test/java/org/jooby/json/YassonParserTest.java new file mode 100644 index 0000000000..5b4f6e618d --- /dev/null +++ b/modules/jooby-yasson/src/test/java/org/jooby/json/YassonParserTest.java @@ -0,0 +1,124 @@ +package org.jooby.json; + +import static org.easymock.EasyMock.expect; +import static org.junit.Assert.assertEquals; + +import javax.json.bind.Jsonb; + +import org.jooby.MediaType; +import org.jooby.Parser; +import org.jooby.Parser.Context; +import org.jooby.test.MockUnit; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; +import com.google.inject.TypeLiteral; + +@RunWith(PowerMockRunner.class) +@PrepareForTest({YassonParser.class, Jsonb.class }) +public class YassonParserTest { + + @SuppressWarnings("unchecked") + @Test + public void parseBody() throws Exception { + TypeLiteral type = TypeLiteral.get(YassonParserTest.class); + Object value = new Object(); + new MockUnit(Jsonb.class, Parser.Context.class, Parser.BodyReference.class) + .expect(unit -> { + Context ctx = unit.get(Parser.Context.class); + expect(ctx.type()).andReturn(MediaType.json); + + Parser.Builder builder = unit.mock(Parser.Builder.class); + + expect(ctx.ifbody(unit.capture(Parser.Callback.class))).andReturn(builder); + expect(builder.ifparam(unit.capture(Parser.Callback.class))).andReturn(builder); + }) + .expect(unit -> { + Parser.BodyReference ref = unit.get(Parser.BodyReference.class); + expect(ref.text()).andReturn("{}"); + }) + .expect(unit -> { + Jsonb jsonb = unit.get(Jsonb.class); + expect(jsonb.fromJson("{}", type.getType())).andReturn(value); + }) + .run(unit -> { + new YassonParser(MediaType.json, unit.get(Jsonb.class)) + .parse(type, unit.get(Parser.Context.class)); + }, unit -> { + unit.captured(Parser.Callback.class).iterator().next() + .invoke(unit.get(Parser.BodyReference.class)); + }); + } + + @SuppressWarnings("unchecked") + @Test + public void parseParam() throws Exception { + TypeLiteral type = TypeLiteral.get(YassonParserTest.class); + Object value = new Object(); + new MockUnit(Jsonb.class, Parser.Context.class, Parser.ParamReference.class) + .expect(unit -> { + Context ctx = unit.get(Parser.Context.class); + expect(ctx.type()).andReturn(MediaType.json); + + Parser.Builder builder = unit.mock(Parser.Builder.class); + + expect(ctx.ifbody(unit.capture(Parser.Callback.class))).andReturn(builder); + expect(builder.ifparam(unit.capture(Parser.Callback.class))).andReturn(builder); + }) + .expect(unit -> { + Parser.ParamReference ref = unit.get(Parser.ParamReference.class); + expect(ref.first()).andReturn("{}"); + }) + .expect(unit -> { + Jsonb jsonb = unit.get(Jsonb.class); + expect(jsonb.fromJson("{}", type.getType())).andReturn(value); + }) + .run(unit -> { + new YassonParser(MediaType.json, unit.get(Jsonb.class)) + .parse(type, unit.get(Parser.Context.class)); + }, unit -> { + unit.captured(Parser.Callback.class).get(1) + .invoke(unit.get(Parser.ParamReference.class)); + }); + } + + @Test + public void next() throws Exception { + TypeLiteral type = TypeLiteral.get(YassonParserTest.class); + new MockUnit(Jsonb.class, Parser.Context.class, Parser.BodyReference.class) + .expect(unit -> { + Context ctx = unit.get(Parser.Context.class); + expect(ctx.type()).andReturn(MediaType.html); + expect(ctx.next()).andReturn(null); + }) + .run(unit -> { + new YassonParser(MediaType.json, unit.get(Jsonb.class)) + .parse(type, unit.get(Parser.Context.class)); + }); + } + + @Test + public void nextAny() throws Exception { + TypeLiteral type = TypeLiteral.get(YassonParserTest.class); + new MockUnit(Jsonb.class, Parser.Context.class, Parser.BodyReference.class) + .expect(unit -> { + Context ctx = unit.get(Parser.Context.class); + expect(ctx.type()).andReturn(MediaType.all); + expect(ctx.next()).andReturn(null); + }) + .run(unit -> { + new YassonParser(MediaType.json, unit.get(Jsonb.class)) + .parse(type, unit.get(Parser.Context.class)); + }); + } + + @Test + public void toStr() throws Exception { + new MockUnit(Jsonb.class) + .run(unit -> { + assertEquals("yasson", new YassonParser(MediaType.json, unit.get(Jsonb.class)).toString()); + }); + } + +} diff --git a/modules/jooby-yasson/src/test/java/org/jooby/json/YassonRendererTest.java b/modules/jooby-yasson/src/test/java/org/jooby/json/YassonRendererTest.java new file mode 100644 index 0000000000..988fbf63cd --- /dev/null +++ b/modules/jooby-yasson/src/test/java/org/jooby/json/YassonRendererTest.java @@ -0,0 +1,102 @@ +package org.jooby.json; + +import static org.easymock.EasyMock.expect; +import static org.junit.Assert.assertEquals; + +import javax.json.bind.Jsonb; + +import org.jooby.MediaType; +import org.jooby.Renderer; +import org.jooby.Renderer.Context; +import org.jooby.test.MockUnit; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; + +@RunWith(PowerMockRunner.class) +@PrepareForTest({YassonRenderer.class, Jsonb.class }) +public class YassonRendererTest { + + @Test + public void render() throws Exception { + Object value = new YassonRendererTest(); + new MockUnit(Jsonb.class, Renderer.Context.class) + .expect(unit -> { + Context ctx = unit.get(Renderer.Context.class); + expect(ctx.accepts(MediaType.json)).andReturn(true); + expect(ctx.type(MediaType.json)).andReturn(ctx); + ctx.send("{}"); + }) + .expect(unit -> { + Jsonb gson = unit.get(Jsonb.class); + expect(gson.toJson(value)).andReturn("{}"); + }) + .run(unit -> { + new YassonRenderer(MediaType.json, unit.get(Jsonb.class)) + .render(value, unit.get(Renderer.Context.class)); + }, unit -> { + }); + } + + @Test + public void renderSkip() throws Exception { + Object value = new YassonRendererTest(); + new MockUnit(Jsonb.class, Renderer.Context.class) + .expect(unit -> { + Context ctx = unit.get(Renderer.Context.class); + expect(ctx.accepts(MediaType.json)).andReturn(false); + }) + .run(unit -> { + new YassonRenderer(MediaType.json, unit.get(Jsonb.class)) + .render(value, unit.get(Renderer.Context.class)); + }, unit -> { + }); + } + + @Test + public void toStr() throws Exception { + new MockUnit(Jsonb.class) + .run(unit -> { + assertEquals("json", new YassonRenderer(MediaType.json, unit.get(Jsonb.class)).toString()); + }); + } + + @Test + public void rawWithCharSequence() throws Exception { + String value = "{\"foo\":\"bar\"}"; + new MockUnit(Jsonb.class, Renderer.Context.class) + .expect(unit -> { + Context ctx = unit.get(Renderer.Context.class); + expect(ctx.type(MediaType.json)).andReturn(ctx); + ctx.send(value); + }) + .run(unit -> { + new YassonRawRenderer(MediaType.json, unit.get(Jsonb.class)) + .render(value, unit.get(Renderer.Context.class)); + }, unit -> { + }); + } + + @Test + public void rawWithObject() throws Exception { + Object value = new YassonRendererTest(); + new MockUnit(Jsonb.class, Renderer.Context.class) + .expect(unit -> { + Context ctx = unit.get(Renderer.Context.class); + expect(ctx.accepts(MediaType.json)).andReturn(true); + expect(ctx.type(MediaType.json)).andReturn(ctx); + ctx.send("{}"); + }) + .expect(unit -> { + Jsonb gson = unit.get(Jsonb.class); + expect(gson.toJson(value)).andReturn("{}"); + }) + .run(unit -> { + new YassonRawRenderer(MediaType.json, unit.get(Jsonb.class)) + .render(value, unit.get(Renderer.Context.class)); + }, unit -> { + }); + } + +} diff --git a/modules/pom.xml b/modules/pom.xml index f33aed46cf..4d9ebc8b33 100644 --- a/modules/pom.xml +++ b/modules/pom.xml @@ -6,13 +6,14 @@ org.jooby jooby-project - 1.5.1-SNAPSHOT + 1.6.9 modules pom + jooby-exposed jooby-apitool jooby-executor jooby-jackson @@ -80,6 +81,7 @@ jooby-rocker jooby-livereload jooby-eventbus + jooby-yasson jooby-frontend jooby-assets diff --git a/pom.xml b/pom.xml index b553c219d3..a3788ad87a 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ 4.0.0 org.jooby jooby-project - 1.5.1-SNAPSHOT + 1.6.9 pom jooby-project @@ -83,6 +83,12 @@ ${jooby.version} + + org.jooby + jooby-exposed + ${jooby.version} + + org.jooby jooby-executor @@ -125,6 +131,12 @@ ${jooby.version} + + org.jooby + jooby-yasson + ${jooby.version} + + org.jooby jooby-maven-plugin @@ -609,9 +621,9 @@ - io.github.lukehutch - fast-classpath-scanner - ${fast-classpath-scanner.version} + io.github.classgraph + classgraph + ${classgraph.version} @@ -899,6 +911,19 @@ ${gson.version} + + + org.eclipse + yasson + ${yasson.version} + + + + org.glassfish + javax.json + ${javax.json.version} + + org.jdbi @@ -1089,14 +1114,21 @@ org.elasticsearch.client - rest - ${elasticsearch} + elasticsearch-rest-high-level-client + ${elasticsearch.version} + + + + + javax.enterprise + cdi-api + ${cdi-api.version} org.hibernate - hibernate-entitymanager + hibernate-core ${hibernate.version} @@ -1114,7 +1146,7 @@ - org.glassfish.web + org.glassfish javax.el ${javax.el-ref.version} @@ -1612,6 +1644,12 @@ + + org.crashub + crash.cli + ${crash.version} + + org.crashub crash.connectors.telnet @@ -3117,14 +3155,15 @@ org.eclipse.jdt.apt.processorOptions/defaultOverwrite=true 2.5.13 4.7 3.0.17 - 6.2 + 7.3.1 1.9.40 2.1.2 1.11.358 3.3.4 - 2.0.8.Final + 2.0.25.Final 2.9.2 2.6.2 + 1.1 2.18.3 3.2.6 v20180610 @@ -3142,7 +3181,7 @@ org.eclipse.jdt.apt.processorOptions/defaultOverwrite=true 11.11.2 11.18.2 2.10.5 - 5.5.3 + 7.5.0 5.1.3 2.3.28 1.6 @@ -3150,29 +3189,31 @@ org.eclipse.jdt.apt.processorOptions/defaultOverwrite=true 2.5.0 25.1-jre 2.8.5 + 1.0.1 + 1.1 4.2.0 1.4.197 4.1.0 - 3.10.2 + 3.11 5.1.3.Final - 5.2.1.Final - 3.2.0 + 5.3.9.Final + 3.3.1 4.5.5 4.6.0 - 2.9.6 + 2.10.1 1.2.7 3.22.0-GA - 2.2.5 - 2.2.6 + 3.0.1-b06 + 3.0.1-b10 1 2.0 1.8.5.Final 3.9.0 2.78 - 3.3.0 + 3.11.1 2.9.0 1.19.4 - 9.4.10.v20180503 + 9.4.24.v20191120 1.4.0 1.11.3 2.1.3 @@ -3180,7 +3221,7 @@ org.eclipse.jdt.apt.processorOptions/defaultOverwrite=true 5.2.0 1.11.3 3.0.2 - 1.2.51 + 1.3.31 1.17.2 1.2 1.2.3 @@ -3191,11 +3232,11 @@ org.eclipse.jdt.apt.processorOptions/defaultOverwrite=true 3.8.0 ${mongo-java-driver.version} 1.3.2 - 5.1.42 + 5.1.47 3.4.0.52.4 3.4.0.52 3.3.2 - 4.1.27.Final + 4.1.43.Final 1.9.9 2.3.1 2.4.0 @@ -3214,16 +3255,17 @@ org.eclipse.jdt.apt.processorOptions/defaultOverwrite=true 3.1.0 1.7.25 1.7.25 - 1.19 + 1.25 2.12.3 1.0.36 3.0.0 3.17.1 1.5.20 - 3.0.9.RELEASE - 2.0.9.Final + 3.0.10.RELEASE + 2.0.28.Final 2.1 2.4.8 + 0.12.1 ** @@ -3233,7 +3275,7 @@ org.eclipse.jdt.apt.processorOptions/defaultOverwrite=true 3.11.2 - 4.1.4 + 4.2.1 2.0.4 @@ -3245,7 +3287,7 @@ org.eclipse.jdt.apt.processorOptions/defaultOverwrite=true 3.5.0 2.5.9 1.1.1 - 3.1.6 + 4.6.18 0.0.8 2.2 1.2.0 @@ -3273,7 +3315,7 @@ org.eclipse.jdt.apt.processorOptions/defaultOverwrite=true 3.1.0 2.1.1 0.4.13 - 0.9.13 + 0.9.18 1.2.1 1.6.0 ${jacoco.version}