Repository: jhipster/generator-jhipster
Pull request #7456 (2018-04-09 23:17:34)

Add a streaming/reactive endpoint for Mongo and Couchbase
- Please make sure the below checklist is followed for Pull Requests.

- [x] [Travis tests](https://travis-ci.org/jhipster/generator-jhipster/pull_requests) are green
- [x] Tests are added where necessary
- [ ] Documentation is added/updated where necessary
- [x] Coding Rules & Commit Guidelines as per our [CONTRIBUTING.md document](https://github.com/jhipster/generator-jhipster/blob/master/CONTRIBUTING.md) are followed

This PR:
- creates a reactive repository if the reactive option is on for Mongo and Couchbase
- creates a streaming reactive WebFlux endpoint with mediatype application/stream+json
- adds a test using WebTestClient for this endpoint

This endpoint has the advantage to be fully reactive end-to-end. It can be used to fetch large collections out of the database without OOM (and without the drawbacks of pagination fetching such as add/delete of entities during the extract and repeated queries to the database).

Cassandra could also be done but this would require to completely move to spring-data-cassandra.
For JPA, there could be some interesting things to do with Scrollable ResultSets but I need to investigate more. 



Patch:
diff --git a/.travis.yml b/.travis.yml
index 59e665fa7d..65b7e3b078 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -4,7 +4,7 @@ services:
   - docker
 language: node_js
 node_js:
-  - "8.11.1"
+  - "8.10.0"
 jdk:
   - oraclejdk8
 addons:
diff --git a/generators/aws-containers/constants.js b/generators/aws-containers/constants.js
index 7f7dfb1139..2b8c8e4885 100644
--- a/generators/aws-containers/constants.js
+++ b/generators/aws-containers/constants.js
@@ -17,12 +17,15 @@
  * limitations under the License.
  */
 
+const AWS_SSM_VERSION = '1.11.247';
+
 const configuration = {
     aws: 'aws'
 };
 
 const constants = {
-    conf: configuration
+    conf: configuration,
+    AWS_SSM_VERSION
 };
 
 module.exports = constants;
diff --git a/generators/aws-containers/index.js b/generators/aws-containers/index.js
index d7fc0497e8..f0de1bb95a 100644
--- a/generators/aws-containers/index.js
+++ b/generators/aws-containers/index.js
@@ -289,10 +289,10 @@ module.exports = class extends BaseGenerator {
                 this.appConfigs.forEach((config) => {
                     const directory = `${this.directoryPath}${config.appFolder}`;
                     if (config.buildTool === 'maven') {
-                        this.addMavenDependencyInDirectory(directory, AWS_SSM_GROUP, AWS_SSM_ARTIFACT);
+                        this.addMavenDependencyInDirectory(directory, AWS_SSM_GROUP, AWS_SSM_ARTIFACT, awsConstants.AWS_SSM_VERSION);
                         this.addMavenDependencyInDirectory(directory, SPRING_CLOUD_GROUP, SPRING_CLOUD_ARTIFACT);
                     } else if (config.buildTool === 'gradle') {
-                        this.addGradleDependencyInDirectory(directory, 'compile', AWS_SSM_GROUP, AWS_SSM_ARTIFACT);
+                        this.addGradleDependencyInDirectory(directory, 'compile', AWS_SSM_GROUP, AWS_SSM_ARTIFACT, awsConstants.AWS_SSM_VERSION);
                         this.addGradleDependencyInDirectory(directory, 'compile', SPRING_CLOUD_GROUP, SPRING_CLOUD_ARTIFACT);
                     }
                 });
diff --git a/generators/aws/index.js b/generators/aws/index.js
index ad3fbf63dd..675816e88f 100644
--- a/generators/aws/index.js
+++ b/generators/aws/index.js
@@ -209,19 +209,6 @@ module.exports = class extends BaseGenerator {
                     }
                 });
             },
-            verifyRoles() {
-                const cb = this.async();
-                this.log();
-                this.log(chalk.bold('Verifying ElasticBeanstalk Roles'));
-                const iam = this.awsFactory.getIam();
-                iam.verifyRoles({}, (err) => {
-                    if (err) {
-                        this.error(chalk.red(err.message));
-                    } else {
-                        cb();
-                    }
-                });
-            },
             createApplication() {
                 const cb = this.async();
                 this.log();
diff --git a/generators/aws/lib/aws.js b/generators/aws/lib/aws.js
index 05141b1221..12c66c0b36 100644
--- a/generators/aws/lib/aws.js
+++ b/generators/aws/lib/aws.js
@@ -2,7 +2,6 @@ const S3 = require('./s3.js');
 const Rds = require('./rds.js');
 const shelljs = require('shelljs');
 const Eb = require('./eb.js');
-const Iam = require('./iam.js');
 
 let Aws;
 let generator;
@@ -41,7 +40,3 @@ AwsFactory.prototype.getRds = function getRds() {
 AwsFactory.prototype.getEb = function getEb() {
     return new Eb(Aws, generator);
 };
-
-AwsFactory.prototype.getIam = function getIa() {
-    return new Iam(Aws, generator);
-};
diff --git a/generators/aws/lib/eb.js b/generators/aws/lib/eb.js
index 70294c9744..eb4b1c6d6d 100644
--- a/generators/aws/lib/eb.js
+++ b/generators/aws/lib/eb.js
@@ -159,6 +159,11 @@ function createEnvironment(params, callback) {
                     Namespace: 'aws:autoscaling:launchconfiguration',
                     OptionName: 'InstanceType',
                     Value: instanceType
+                },
+                {
+                    Namespace: 'aws:autoscaling:launchconfiguration',
+                    OptionName: 'IamInstanceProfile',
+                    Value: 'aws-elasticbeanstalk-ec2-role'
                 }
             ],
             SolutionStackName: solutionStackName,
diff --git a/generators/aws/lib/iam.js b/generators/aws/lib/iam.js
deleted file mode 100644
index 5029ca1bf6..0000000000
--- a/generators/aws/lib/iam.js
+++ /dev/null
@@ -1,140 +0,0 @@
-const INSTANCE_PROFILE_ROLE = 'aws-elasticbeanstalk-ec2-role';
-const SERVICE_PROFILE_ROLE = 'aws-elasticbeanstalk-service-role';
-const AWS_POLICY_ARN = suffix => `arn:aws:iam::aws:policy/${suffix}`;
-const AWS_SERVICE_ARN = suffix => `arn:aws:iam::aws:policy/service-role/${suffix}`;
-
-let aws;
-let log;
-
-const Iam = module.exports = function Iam(Aws, generator) {
-    aws = Aws;
-    log = generator.log;
-};
-
-const createRole = (RoleName, Description, AssumeRolePolicyDocument) => {
-    const iam = new aws.IAM();
-    return iam.createRole({
-        RoleName,
-        Description,
-        AssumeRolePolicyDocument
-    }).promise();
-};
-
-const attachRolePolicy = (PolicyArn, RoleName) => {
-    const iam = new aws.IAM();
-    return iam.attachRolePolicy({ PolicyArn, RoleName }).promise();
-};
-
-
-const attachServicePolicyToRole = (policySuffix, roleName) => attachRolePolicy(AWS_SERVICE_ARN(policySuffix), roleName);
-const attachPolicyToRole = (policySuffix, roleName) => attachRolePolicy(AWS_POLICY_ARN(policySuffix), roleName);
-
-const getRole = (RoleName) => {
-    const iam = new aws.IAM();
-    return iam.getRole({ RoleName }).promise();
-};
-
-const hasRole = roleName => getRole(roleName).then(() => true).catch((err) => {
-    if (err && err.code === 'NoSuchEntity') {
-        return false;
-    }
-    throw err;
-});
-
-const hasInstanceProfile = () => hasRole(INSTANCE_PROFILE_ROLE);
-const hasServiceProfile = () => hasRole(SERVICE_PROFILE_ROLE);
-
-
-const createServiceProfileWithAttachedPolicies = () => {
-    const roleName = SERVICE_PROFILE_ROLE;
-    const description = 'Default Elastic Beanstalk Service profile created by JHipster.';
-    const assumedPolicyDoc = `{
-  "Version": "2012-10-17",
-  "Statement": [
-    {
-      "Effect": "Allow",
-      "Principal": {
-        "Service": "elasticbeanstalk.amazonaws.com"
-      },
-      "Action": "sts:AssumeRole",
-      "Condition": {
-        "StringEquals": {
-          "sts:ExternalId": "elasticbeanstalk"
-        }
-      }
-    }
-  ]
-}`;
-
-    return createRole(roleName, description, assumedPolicyDoc)
-        .then(() => {
-            const policiesToAttach = [
-                attachServicePolicyToRole('AWSElasticBeanstalkEnhancedHealth', roleName),
-                attachServicePolicyToRole('AWSElasticBeanstalkService', roleName)
-            ];
-            return Promise.all(policiesToAttach);
-        });
-};
-
-const createInstanceProfileWithAttachedPolicies = () => {
-    const roleName = INSTANCE_PROFILE_ROLE;
-    const description = 'Default Elastic Beanstalk instance profile created by JHipster.';
-    const assumedPolicyDoc = `{
-  "Version": "2008-10-17",
-  "Statement": [
-    {
-      "Effect": "Allow",
-      "Principal": {
-        "Service": "ec2.amazonaws.com"
-      },
-      "Action": "sts:AssumeRole"
-    }
-  ]
-}`;
-
-    return createRole(roleName, description, assumedPolicyDoc)
-        .then(() => {
-            const policiesToAttach = [
-                attachPolicyToRole('AWSElasticBeanstalkWebTier', roleName),
-                attachPolicyToRole('AWSElasticBeanstalkWorkerTier', roleName),
-                attachPolicyToRole('AWSElasticBeanstalkMulticontainerDocker', roleName)
-            ];
-            return Promise.all(policiesToAttach);
-        });
-};
-
-
-/**
- * Verifies that the Elastic Beanstalk roles have been created in the IAM Account. This is for situations
- * where we're deploying to a new/fresh AWS account, and an Elastic Beanstalk application has not been deployed via
- * the web-application or CLI.
- *
- * See [service role info here]{@link https://docs.aws.amazon.com/elasticbeanstalk/latest/dg/iam-servicerole.html}
- * and [instance profile info here]{@link https://docs.aws.amazon.com/elasticbeanstalk/latest/dg/iam-instanceprofile.html#iam-instanceprofile-verify}
- * @param params
- * @param callback
- */
-Iam.prototype.verifyRoles = function verifyRoles(params, callback) {
-    hasInstanceProfile()
-        .then((instanceProfileExists) => {
-            if (!instanceProfileExists) {
-                log(`Instance profile '${INSTANCE_PROFILE_ROLE}' does not exist. Creating based on defaults.`);
-                return createInstanceProfileWithAttachedPolicies();
-            }
-
-            return instanceProfileExists;
-        })
-        .then(() => hasServiceProfile())
-        .then((serviceProfileExists) => {
-            if (!serviceProfileExists) {
-                log(`Service Profile profile '${SERVICE_PROFILE_ROLE}' does not exist. Creating based on defaults.`);
-                return createServiceProfileWithAttachedPolicies();
-            }
-
-            return serviceProfileExists;
-        })
-        .then(() => callback(null, null))
-        .catch((err) => {
-            callback({ message: err.message }, null);
-        });
-};
diff --git a/generators/aws/lib/rds.js b/generators/aws/lib/rds.js
index 817dc2ced1..2eb6a207b4 100644
--- a/generators/aws/lib/rds.js
+++ b/generators/aws/lib/rds.js
@@ -18,7 +18,7 @@ Rds.prototype.createDatabase = function createDatabase(params, callback) {
             const rdsSecurityGroupId = data.rdsSecurityGroupId;
 
             if (!rdsSecurityGroupId) {
-                callback(null, { message: `Database ${dbName} already exists (based on security group)` });
+                callback(null, { message: `Database ${dbName} already exists` });
             } else {
                 authorizeSecurityGroupIngress({ rdsSecurityGroupId }, (err) => {
                     if (err) {
diff --git a/generators/aws/lib/s3.js b/generators/aws/lib/s3.js
index 884c75f558..d7ef9d2a25 100644
--- a/generators/aws/lib/s3.js
+++ b/generators/aws/lib/s3.js
@@ -5,6 +5,7 @@ const S3_STANDARD_REGION = 'us-east-1';
 
 let Progressbar;
 
+
 const S3 = module.exports = function S3(Aws, generator) {
     this.Aws = Aws;
     try {
@@ -23,7 +24,7 @@ S3.prototype.createBucket = function createBucket(params, callback) {
         CreateBucketConfiguration: { LocationConstraint: region }
     };
 
-    if (region === S3_STANDARD_REGION) {
+    if (region.toLowerCase() === S3_STANDARD_REGION) {
         s3Params.CreateBucketConfiguration = undefined;
     }
 
diff --git a/generators/client/templates/angular/src/main/webapp/app/admin/logs/logs.component.html.ejs b/generators/client/templates/angular/src/main/webapp/app/admin/logs/logs.component.html.ejs
index cf3f1a9e9f..fa52f4e9f0 100644
--- a/generators/client/templates/angular/src/main/webapp/app/admin/logs/logs.component.html.ejs
+++ b/generators/client/templates/angular/src/main/webapp/app/admin/logs/logs.component.html.ejs
@@ -34,12 +34,11 @@
         <tr *ngFor="let logger of (loggers | pureFilter:filter:'name' | orderBy:orderProp:reverse)">
             <td><small>{{logger.name | slice:0:140}}</small></td>
             <td>
-                <button (click)="changeLevel(logger.name, 'TRACE')" [ngClass]="(logger.level=='TRACE') ? 'btn-primary' : 'btn-light'" class="btn btn-sm">TRACE</button>
-                <button (click)="changeLevel(logger.name, 'DEBUG')" [ngClass]="(logger.level=='DEBUG') ? 'btn-success' : 'btn-light'" class="btn btn-sm">DEBUG</button>
+                <button (click)="changeLevel(logger.name, 'TRACE')" [ngClass]="(logger.level=='TRACE') ? 'btn-danger' : 'btn-light'" class="btn btn-sm">TRACE</button>
+                <button (click)="changeLevel(logger.name, 'DEBUG')" [ngClass]="(logger.level=='DEBUG') ? 'btn-warning' : 'btn-light'" class="btn btn-sm">DEBUG</button>
                 <button (click)="changeLevel(logger.name, 'INFO')" [ngClass]="(logger.level=='INFO') ? 'btn-info' : 'btn-light'" class="btn btn-sm">INFO</button>
-                <button (click)="changeLevel(logger.name, 'WARN')" [ngClass]="(logger.level=='WARN') ? 'btn-warning' : 'btn-light'" class="btn btn-sm">WARN</button>
-                <button (click)="changeLevel(logger.name, 'ERROR')" [ngClass]="(logger.level=='ERROR') ? 'btn-danger' : 'btn-light'" class="btn btn-sm">ERROR</button>
-                <button (click)="changeLevel(logger.name, 'OFF')" [ngClass]="(logger.level=='OFF') ? 'btn-secondary' : 'btn-light'" class="btn btn-sm">OFF</button>
+                <button (click)="changeLevel(logger.name, 'WARN')" [ngClass]="(logger.level=='WARN') ? 'btn-success' : 'btn-light'" class="btn btn-sm">WARN</button>
+                <button (click)="changeLevel(logger.name, 'ERROR')" [ngClass]="(logger.level=='ERROR') ? 'btn-primary' : 'btn-light'" class="btn btn-sm">ERROR</button>
             </td>
         </tr>
     </table>
diff --git a/generators/client/templates/react/src/main/webapp/app/modules/administration/logs/logs.tsx.ejs b/generators/client/templates/react/src/main/webapp/app/modules/administration/logs/logs.tsx.ejs
index dbf573a74b..f9025a3623 100644
--- a/generators/client/templates/react/src/main/webapp/app/modules/administration/logs/logs.tsx.ejs
+++ b/generators/client/templates/react/src/main/webapp/app/modules/administration/logs/logs.tsx.ejs
@@ -88,12 +88,11 @@ export class LogsPage extends React.Component<ILogsPageProps, ILogsPageState> {
                 <tr key={`log-row-${i}`}>
                   <td><small>{logger.name}</small></td>
                   <td>
-                    <button disabled={isFetching} onClick={this.changeLevel(logger.name, 'TRACE')} className={this.getClassName(logger.level, 'TRACE', 'primary')}>TRACE</button>
-                    <button disabled={isFetching} onClick={this.changeLevel(logger.name, 'DEBUG')} className={this.getClassName(logger.level, 'DEBUG', 'success')}>DEBUG</button>
+                    <button disabled={isFetching} onClick={this.changeLevel(logger.name, 'TRACE')} className={this.getClassName(logger.level, 'TRACE', 'danger')}>TRACE</button>
+                    <button disabled={isFetching} onClick={this.changeLevel(logger.name, 'DEBUG')} className={this.getClassName(logger.level, 'DEBUG', 'warning')}>DEBUG</button>
                     <button disabled={isFetching} onClick={this.changeLevel(logger.name, 'INFO')} className={this.getClassName(logger.level, 'INFO', 'info')}>INFO</button>
-                    <button disabled={isFetching} onClick={this.changeLevel(logger.name, 'WARN')} className={this.getClassName(logger.level, 'WARN', 'warning')}>WARN</button>
-                    <button disabled={isFetching} onClick={this.changeLevel(logger.name, 'ERROR')} className={this.getClassName(logger.level, 'ERROR', 'danger')}>ERROR</button>
-                    <button disabled={isFetching} onClick={this.changeLevel(logger.name, 'OFF')} className={this.getClassName(logger.level, 'OFF', 'secondary')}>OFF</button>
+                    <button disabled={isFetching} onClick={this.changeLevel(logger.name, 'WARN')} className={this.getClassName(logger.level, 'WARN', 'success')}>WARN</button>
+                    <button disabled={isFetching} onClick={this.changeLevel(logger.name, 'ERROR')} className={this.getClassName(logger.level, 'ERROR', 'primary')}>ERROR</button>
                   </td>
                 </tr>
               )
diff --git a/generators/entity-server/files.js b/generators/entity-server/files.js
index 4d4008dc18..52a27f46f7 100644
--- a/generators/entity-server/files.js
+++ b/generators/entity-server/files.js
@@ -103,6 +103,14 @@ const serverFiles = {
                 renameTo: generator => `${generator.packageFolder}/repository/search/${generator.entityClass}SearchRepository.java`
             }]
         },
+        {
+            condition: generator => (generator.reactive && ['mongodb', 'couchbase'].includes(generator.databaseType)),
+            path: SERVER_MAIN_SRC_DIR,
+            templates: [{
+                file: 'package/repository/reactive/EntityReactiveRepository.java',
+                renameTo: generator => `${generator.packageFolder}/repository/reactive/${generator.entityClass}ReactiveRepository.java`
+            }]
+        },
         {
             condition: generator => generator.service === 'serviceImpl',
             path: SERVER_MAIN_SRC_DIR,
diff --git a/generators/entity-server/templates/src/main/java/package/common/inject_template.ejs b/generators/entity-server/templates/src/main/java/package/common/inject_template.ejs
index 8e7ff65b48..1e44ac5f0f 100644
--- a/generators/entity-server/templates/src/main/java/package/common/inject_template.ejs
+++ b/generators/entity-server/templates/src/main/java/package/common/inject_template.ejs
@@ -27,6 +27,10 @@
 
     private final <%= entityClass %>SearchRepository <%= entityInstance %>SearchRepository;
     <%_ } _%>
+    <%_ if (reactiveRepositories) { _%>
+
+    private final <%= entityClass %>ReactiveRepository <%= entityInstance %>ReactiveRepository;
+    <%_ } _%>
 <%_  } else { _%>
 
     private final <%= entityClass %>Service <%= entityInstance %>Service;
@@ -36,7 +40,7 @@
     <%_ } _%>
 <%_ } _%>
 
-    public <%= constructorName %>(<% if (!viaService) { %><%= entityClass %>Repository <%= entityInstance %>Repository<% if (dto === 'mapstruct') { %>, <%= entityClass %>Mapper <%= entityInstance %>Mapper<% } %><% if (searchEngine === 'elasticsearch') { %>, <%= entityClass %>SearchRepository <%= entityInstance %>SearchRepository<% } %><%  } else { %><%= entityClass %>Service <%= entityInstance %>Service<% } %><% if (queryService && viaService) { %>, <%= entityClass %>QueryService <%= entityInstance %>QueryService<% } %>) {
+    public <%= constructorName %>(<% if (!viaService) { %><%= entityClass %>Repository <%= entityInstance %>Repository<% if (dto === 'mapstruct') { %>, <%= entityClass %>Mapper <%= entityInstance %>Mapper<% } %><% if (searchEngine === 'elasticsearch') { %>, <%= entityClass %>SearchRepository <%= entityInstance %>SearchRepository<% } %><% if (reactiveRepositories) { %>, <%= entityClass %>ReactiveRepository <%= entityInstance %>ReactiveRepository<% } %><%  } else { %><%= entityClass %>Service <%= entityInstance %>Service<% } %><% if (queryService && viaService) { %>, <%= entityClass %>QueryService <%= entityInstance %>QueryService<% } %>) {
         <%_ if (!viaService) { _%>
         this.<%= entityInstance %>Repository = <%= entityInstance %>Repository;
             <%_ if (dto === 'mapstruct') { _%>
@@ -45,6 +49,9 @@
             <%_ if (searchEngine === 'elasticsearch') { _%>
         this.<%= entityInstance %>SearchRepository = <%= entityInstance %>SearchRepository;
             <%_ } _%>
+            <%_ if (reactiveRepositories) { _%>
+        this.<%= entityInstance %>ReactiveRepository = <%= entityInstance %>ReactiveRepository;
+            <%_ } _%>
         <%_  } else { _%>
         this.<%= entityInstance %>Service = <%= entityInstance %>Service;
             <%_ if (queryService) {  _%>
diff --git a/generators/entity-server/templates/src/main/java/package/repository/reactive/EntityReactiveRepository.java.ejs b/generators/entity-server/templates/src/main/java/package/repository/reactive/EntityReactiveRepository.java.ejs
new file mode 100644
index 0000000000..c63ea5ccbe
--- /dev/null
+++ b/generators/entity-server/templates/src/main/java/package/repository/reactive/EntityReactiveRepository.java.ejs
@@ -0,0 +1,49 @@
+<%#
+ Copyright 2013-2018 the original author or authors from the JHipster project.
+
+ This file is part of the JHipster project, see https://www.jhipster.tech/
+ for more information.
+
+ 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 <%= packageName %>.repository.reactive;
+
+import <%= packageName %>.domain.<%= entityClass %>;
+<%_ if (databaseType === 'cassandra') { _%>
+import org.springframework.data.cassandra.repository.ReactiveCassandraRepository;
+<%_ } _%>
+<%_ if (databaseType === 'couchbase') { _%>
+import org.springframework.data.couchbase.core.query.Query;
+import org.springframework.data.couchbase.repository.ReactiveCouchbaseSortingRepository;
+<%_ } _%>
+<%_ if (databaseType === 'mongodb') { _%>
+import org.springframework.data.mongodb.repository.ReactiveMongoRepository;
+<%_ } _%>
+import org.springframework.stereotype.Repository;
+<%_ if (databaseType === 'couchbase') { _%>
+import reactor.core.publisher.Flux;
+<%_ } _%>
+
+/**
+ * Spring Data <% if (databaseType === 'mongodb') { %>MongoDB<% } if (databaseType === 'couchbase') { %>Couchbase<% } if (databaseType === 'cassandra') { %>Cassandra<% } %> reactive repository for the <%= entityClass %> entity.
+ */
+@SuppressWarnings("unused")
+@Repository
+public interface <%= entityClass %>ReactiveRepository extends Reactive<% if (databaseType === 'mongodb') { %>Mongo<% } if (databaseType === 'couchbase') { %>CouchbaseSorting<% } if (databaseType === 'cassandra') { %>Cassandra<% } %>Repository<<%= entityClass %>, <%= pkType %>> {
+    <%_ if (databaseType === 'couchbase') { _%>
+
+    @Query("#{#n1ql.selectEntity} WHERE #{#n1ql.filter}")
+    Flux<<%= entityClass %>> findAll();
+
+    <%_ } _%>
+}
\ No newline at end of file
diff --git a/generators/entity-server/templates/src/main/java/package/service/EntityService.java.ejs b/generators/entity-server/templates/src/main/java/package/service/EntityService.java.ejs
index 3b4b1d5444..41b0f6dff7 100644
--- a/generators/entity-server/templates/src/main/java/package/service/EntityService.java.ejs
+++ b/generators/entity-server/templates/src/main/java/package/service/EntityService.java.ejs
@@ -29,6 +29,9 @@ import <%=packageName%>.domain.<%= entityClass %>;
 import org.springframework.data.domain.Page;
 import org.springframework.data.domain.Pageable;
 <%_ } _%>
+<%_ if (reactiveRepositories) { _%>
+import reactor.core.publisher.Flux;
+<%_ } _%>
 
 <%_ if (pagination === 'no' || fieldsContainNoOwnerOneToOne === true) { _%>
 import java.util.List;
@@ -73,6 +76,14 @@ public interface <%= entityClass %>Service {
     Page<<%= instanceType %>> findAllWithEagerRelationships(Pageable pageable);
     <% } -%>
 
+    <%_ if (reactiveRepositories) { _%>
+    /**
+     * Get all the <%= entityInstancePlural %>.
+     * @return the Flux of entities
+     */
+    Flux<<%= instanceType %>> findAllAsFlux();
+
+    <%_ } _%>
     /**
      * Get the "id" <%= entityInstance %>.
      *
diff --git a/generators/entity-server/templates/src/main/java/package/service/impl/EntityServiceImpl.java.ejs b/generators/entity-server/templates/src/main/java/package/service/impl/EntityServiceImpl.java.ejs
index 4bbbe8dfec..f025d21f0b 100644
--- a/generators/entity-server/templates/src/main/java/package/service/impl/EntityServiceImpl.java.ejs
+++ b/generators/entity-server/templates/src/main/java/package/service/impl/EntityServiceImpl.java.ejs
@@ -16,7 +16,7 @@
  See the License for the specific language governing permissions and
  limitations under the License.
 -%>
-package <%=packageName%>.service<% if (service === 'serviceImpl') { %>.impl<% } %>;
+package <%= packageName %>.service<% if (service === 'serviceImpl') { %>.impl<% } %>;
 <%  const serviceClassName = service === 'serviceImpl' ? entityClass + 'ServiceImpl' : entityClass + 'Service';
     let viaService = false;
     const instanceType = (dto === 'mapstruct') ? entityClass + 'DTO' : entityClass;
@@ -28,12 +28,19 @@ package <%=packageName%>.service<% if (service === 'serviceImpl') { %>.impl<% }
     const repository = entityInstance  + 'Repository';
     const searchRepository = entityInstance  + 'SearchRepository';
     if (service === 'serviceImpl') { %>
-import <%=packageName%>.service.<%= entityClass %>Service;<% } %>
-import <%=packageName%>.domain.<%= entityClass %>;
-import <%=packageName%>.repository.<%= entityClass %>Repository;<% if (searchEngine === 'elasticsearch') { %>
-import <%=packageName%>.repository.search.<%= entityClass %>SearchRepository;<% } if (dto === 'mapstruct') { %>
-import <%=packageName%>.service.dto.<%= entityClass %>DTO;
-import <%=packageName%>.service.mapper.<%= entityClass %>Mapper;<% } %>
+import <%= packageName %>.service.<%= entityClass %>Service;<% } %>
+import <%= packageName %>.domain.<%= entityClass %>;
+import <%= packageName %>.repository.<%= entityClass %>Repository;
+<%_ if (reactiveRepositories) { _%>
+import <%= packageName %>.repository.reactive.<%= entityClass %>ReactiveRepository;
+<%_ } _%>
+<%_ if (searchEngine === 'elasticsearch') { _%>
+import <%= packageName %>.repository.search.<%= entityClass %>SearchRepository;
+<%_ } _%>
+<%_ if (dto === 'mapstruct') { _%>
+import <%= packageName %>.service.dto.<%= entityClass %>DTO;
+import <%= packageName %>.service.mapper.<%= entityClass %>Mapper;
+<%_ } _%>
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -45,11 +52,14 @@ import org.springframework.stereotype.Service;
 <%_ if (databaseType === 'sql') { _%>
 import org.springframework.transaction.annotation.Transactional;
 <%_ } _%>
+<%_ if (reactiveRepositories) { _%>
+import reactor.core.publisher.Flux;
+<%_ } _%>
 
-import java.util.Optional;
 <%_ if (dto === 'mapstruct' && (pagination === 'no' ||  fieldsContainNoOwnerOneToOne === true)) { _%>
 import java.util.LinkedList;<% } %><% if (pagination === 'no' ||  fieldsContainNoOwnerOneToOne === true) { %>
-import java.util.List;<% } %><% if (databaseType === 'cassandra') { %>
+import java.util.List;<% } %>
+import java.util.Optional;<% if (databaseType === 'cassandra') { %>
 import java.util.UUID;<% } %><% if (fieldsContainNoOwnerOneToOne === true || (pagination === 'no' && ((searchEngine === 'elasticsearch' && !viaService) || dto === 'mapstruct'))) { %>
 import java.util.stream.Collectors;<% } %><% if (fieldsContainNoOwnerOneToOne === true || (pagination === 'no' && searchEngine === 'elasticsearch' && !viaService)) { %>
 import java.util.stream.StreamSupport;<% } %><% if (searchEngine === 'elasticsearch') { %>
@@ -103,6 +113,18 @@ public class <%= serviceClassName %><% if (service === 'serviceImpl') { %> imple
             .map(<%= entityToDtoReference %>);<% } %>
         <%_ } _%>
     }
+    <%_ if (reactiveRepositories) { _%>
+
+    /**
+     * Get all the <%= entityInstancePlural %>.
+     * @return the Flux of entities
+     */
+    public Flux<<%= instanceType %>> findAllAsFlux() {
+        log.debug("Request to get all <%= entityClassPlural %> as a flux");
+        return <%= entityInstance %>ReactiveRepository.findAll()<% if (dto === 'mapstruct') { %>
+            .map(<%= entityToDtoReference %>)<% } %>;
+    }
+    <%_ } _%>
     <%_ if (fieldsContainOwnerManyToMany === true) { _%>
 
     /**
diff --git a/generators/entity-server/templates/src/main/java/package/web/rest/EntityResource.java.ejs b/generators/entity-server/templates/src/main/java/package/web/rest/EntityResource.java.ejs
index 37683217cc..afef14d728 100644
--- a/generators/entity-server/templates/src/main/java/package/web/rest/EntityResource.java.ejs
+++ b/generators/entity-server/templates/src/main/java/package/web/rest/EntityResource.java.ejs
@@ -23,9 +23,16 @@ import com.codahale.metrics.annotation.Timed;
 import <%=packageName%>.domain.<%= entityClass %>;
 <%_ } _%>
 <%_ if (service !== 'no') { _%>
-import <%=packageName%>.service.<%= entityClass %>Service;<% } else { %>
-import <%=packageName%>.repository.<%= entityClass %>Repository;<% if (searchEngine === 'elasticsearch') { %>
-import <%=packageName%>.repository.search.<%= entityClass %>SearchRepository;<% }} %>
+import <%=packageName%>.service.<%= entityClass %>Service;
+<%_ } else { _%>
+import <%=packageName%>.repository.<%= entityClass %>Repository;
+    <%_ if (reactiveRepositories) { _%>
+import <%=packageName%>.repository.reactive.<%= entityClass %>ReactiveRepository;
+    <%_ } _%>
+    <%_ if (searchEngine === 'elasticsearch') { _%>
+import <%=packageName%>.repository.search.<%= entityClass %>SearchRepository;
+    <%_ } _%>
+<%_ } _%>
 import <%=packageName%>.web.rest.errors.BadRequestAlertException;
 import <%=packageName%>.web.rest.util.HeaderUtil;<% if (pagination !== 'no') { %>
 import <%=packageName%>.web.rest.util.PaginationUtil;<% } %>
@@ -47,10 +54,18 @@ import org.springframework.data.domain.Pageable;
 import org.springframework.http.HttpHeaders;
 import org.springframework.http.HttpStatus;
 <%_ } _%>
+<%_ if (reactiveRepositories) { _%>
+import org.springframework.http.MediaType;
+<%_ } _%>
 import org.springframework.http.ResponseEntity;
 import org.springframework.web.bind.annotation.*;
-<% if (validation) { %>
-import javax.validation.Valid;<% } %>
+<%_ if (reactiveRepositories) { _%>
+import reactor.core.publisher.Flux;
+<%_ } _%>
+
+<%_ if (validation) { _%>
+import javax.validation.Valid;
+<%_ } _%>
 import java.net.URI;
 import java.net.URISyntaxException;
 <%_ const viaService = service !== 'no';
@@ -135,6 +150,23 @@ public class <%= entityClass %>Resource {
     @GetMapping("/<%= entityApiUrl %>")
     @Timed<%- include('../../common/get_all_template', {viaService: viaService}); -%>
 
+    <%_ if (reactiveRepositories) { _%>
+    /**
+     * GET  /<%= entityApiUrl %> : get all the <%= entityInstancePlural %> as a stream.
+     * @return the Flux of <%= entityInstancePlural %>
+     */
+    @GetMapping(value = "/<%= entityApiUrl %>", produces = MediaType.APPLICATION_STREAM_JSON_VALUE)
+    @Timed
+    public Flux<<%= instanceType %>> getAll<%= entityClassPlural %>AsStream() {
+        log.debug("REST request to get all <%= entityClassPlural %> as a stream");
+        <%_ if (viaService) { _%>
+        return <%= entityInstance %>Service.findAllAsFlux();
+        <%_ } else { _%>
+        return <%= entityInstance %>ReactiveRepository.findAll();
+        <%_ } _%>
+    }
+
+    <%_ } _%>
     /**
      * GET  /<%= entityApiUrl %>/:id : get the "id" <%= entityInstance %>.
      *
diff --git a/generators/entity/index.js b/generators/entity/index.js
index 0d40db515a..992307c888 100644
--- a/generators/entity/index.js
+++ b/generators/entity/index.js
@@ -133,6 +133,7 @@ module.exports = class extends BaseGenerator {
                 this.env.options.appPath = this.config.get('appPath') || constants.CLIENT_MAIN_SRC_DIR;
                 context.options = this.options;
                 context.baseName = this.config.get('baseName');
+                context.reactive = this.config.get('reactive');
                 context.capitalizedBaseName = _.upperFirst(context.baseName);
                 context.packageName = this.config.get('packageName');
                 context.applicationType = this.config.get('applicationType');
@@ -473,6 +474,7 @@ module.exports = class extends BaseGenerator {
                 context.entityTranslationKey = context.clientRootFolder ? _.camelCase(`${context.clientRootFolder}-${context.entityInstance}`) : context.entityInstance;
                 context.entityTranslationKeyMenu = _.camelCase(context.clientRootFolder ? `${context.clientRootFolder}-${context.entityStateName}` : context.entityStateName);
                 context.jhiTablePrefix = this.getTableName(context.jhiPrefix);
+                context.reactiveRepositories = context.reactive && ['mongodb', 'couchbase'].includes(context.databaseType);
 
                 context.fieldsContainDate = false;
                 context.fieldsContainInstant = false;
diff --git a/generators/generator-constants.js b/generators/generator-constants.js
index 50e8aef1f7..2149d23df8 100644
--- a/generators/generator-constants.js
+++ b/generators/generator-constants.js
@@ -57,9 +57,9 @@ const JAVA_VERSION = '1.8'; // Java version is forced to be 1.8. We keep the var
 const SCALA_VERSION = '2.12.1';
 
 // version of Node, Yarn, NPM
-const NODE_VERSION = '8.11.1';
+const NODE_VERSION = '8.10.0';
 const YARN_VERSION = '1.5.1';
-const NPM_VERSION = '5.8.0';
+const NPM_VERSION = '5.7.1';
 
 // all constants used throughout all generators
 
diff --git a/generators/server/prompts.js b/generators/server/prompts.js
index 882df714fb..99ecd07666 100644
--- a/generators/server/prompts.js
+++ b/generators/server/prompts.js
@@ -162,6 +162,10 @@ function askForServerSideOpts(meta) {
                         value: 'mongodb',
                         name: 'MongoDB'
                     },
+                    {
+                        value: 'cassandra',
+                        name: 'Cassandra'
+                    },
                     {
                         value: 'couchbase',
                         name: '[BETA] Couchbase'
@@ -175,12 +179,6 @@ function askForServerSideOpts(meta) {
                         name: 'No database'
                     });
                 }
-                if (response.authenticationType !== 'oauth2') {
-                    opts.push({
-                        value: 'cassandra',
-                        name: 'Cassandra'
-                    });
-                }
                 return opts;
             },
             default: 0
diff --git a/generators/server/templates/build.gradle.ejs b/generators/server/templates/build.gradle.ejs
index 78d9121cd5..d0a74fca46 100644
--- a/generators/server/templates/build.gradle.ejs
+++ b/generators/server/templates/build.gradle.ejs
@@ -297,7 +297,7 @@ dependencies {
     compile "net.java.dev.jna:jna"
     <%_ } _%>
     <%_ if (databaseType === 'mongodb' || databaseType === 'couchbase') { _%>
-    compile "org.springframework.boot:spring-boot-starter-data-<%=databaseType%>"
+    compile "org.springframework.boot:spring-boot-starter-data-<%=databaseType%><% if (reactive === true) { %>-reactive<% } %>"
     <%_ } _%>
     <%_ if (messageBroker === 'kafka') { _%>
     compile "org.springframework.cloud:spring-cloud-stream"
@@ -318,6 +318,7 @@ dependencies {
     compile "org.springframework.boot:spring-boot-starter-thymeleaf"
     compile "org.zalando:problem-spring-web"
     <%_ if (databaseType === 'cassandra') { _%>
+    compile "com.google.guava:guava:18.0"
     compile "com.datastax.cassandra:cassandra-driver-core"
     compile "com.datastax.cassandra:cassandra-driver-extras"
     compile "com.datastax.cassandra:cassandra-driver-mapping"
@@ -361,9 +362,6 @@ dependencies {
     compile "org.springframework.security:spring-security-jwt"
         <%_ } _%>
     <%_ } _%>
-    <%_ if (authenticationType === 'session') { _%>
-    compile "com.google.guava:guava"
-    <%_ } _%>
     <%_ if (authenticationType === 'jwt') { _%>
     compile "io.jsonwebtoken:jjwt"
     <%_ } _%>
@@ -373,6 +371,7 @@ dependencies {
     <%_ } _%>
     <%_ if (databaseType === 'mongodb') { _%>
     compile "com.github.mongobee:mongobee"
+    compile "com.google.guava:guava"
     <%_ } _%>
     <%_ if (databaseType === 'couchbase') { _%>
         compile "com.github.differentway:couchmove"
diff --git a/generators/server/templates/pom.xml.ejs b/generators/server/templates/pom.xml.ejs
index ee0ff4fd92..1c9f71b4d4 100644
--- a/generators/server/templates/pom.xml.ejs
+++ b/generators/server/templates/pom.xml.ejs
@@ -437,6 +437,10 @@
             <artifactId>logstash-logback-encoder</artifactId>
         </dependency>
         <%_ if (databaseType === 'mongodb') { _%>
+        <dependency>
+            <groupId>com.google.guava</groupId>
+            <artifactId>guava</artifactId>
+        </dependency>
         <dependency>
             <groupId>com.github.mongobee</groupId>
             <artifactId>mongobee</artifactId>
@@ -518,7 +522,7 @@
         <%_ if (databaseType === 'mongodb' || databaseType === 'couchbase') { _%>
         <dependency>
             <groupId>org.springframework.boot</groupId>
-            <artifactId>spring-boot-starter-data-<%=databaseType%></artifactId>
+            <artifactId>spring-boot-starter-data-<%=databaseType%><% if (reactive === true) { %>-reactive<% } %></artifactId>
         </dependency>
         <%_ } _%>
         <dependency>
@@ -604,12 +608,6 @@
         </dependency>
             <%_ } _%>
         <%_ } _%>
-        <%_ if (authenticationType === 'session') { _%>
-        <dependency>
-            <groupId>com.google.guava</groupId>
-            <artifactId>guava</artifactId>
-        </dependency>
-        <%_ } _%>
         <%_ if (authenticationType === 'jwt') { _%>
         <dependency>
             <groupId>io.jsonwebtoken</groupId>
diff --git a/generators/server/templates/src/main/java/package/config/DatabaseConfiguration.java.ejs b/generators/server/templates/src/main/java/package/config/DatabaseConfiguration.java.ejs
index 9f2a008bce..cae8dfb48b 100644
--- a/generators/server/templates/src/main/java/package/config/DatabaseConfiguration.java.ejs
+++ b/generators/server/templates/src/main/java/package/config/DatabaseConfiguration.java.ejs
@@ -46,8 +46,15 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 <%_ if (databaseType === 'mongodb') { _%>
 import org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration;
-import org.springframework.boot.autoconfigure.mongo.MongoProperties;<% } %><% if (databaseType === 'couchbase') { %>
-import org.springframework.boot.autoconfigure.couchbase.CouchbaseAutoConfiguration;<% } %><% if (databaseType === 'sql') { %>
+import org.springframework.boot.autoconfigure.mongo.MongoProperties;
+    <%_ if (reactive) { _%>
+import org.springframework.boot.autoconfigure.mongo.MongoReactiveAutoConfiguration;
+    <%_ } _%>
+<%_ } _%>
+<%_ if (databaseType === 'couchbase') { _%>
+import org.springframework.boot.autoconfigure.couchbase.CouchbaseAutoConfiguration;
+<%_ } _%>
+<%_ if (databaseType === 'sql') { _%>
 import org.springframework.beans.factory.annotation.Qualifier;
 import org.springframework.boot.autoconfigure.liquibase.LiquibaseProperties;<% } %>
 import org.springframework.context.annotation.Bean;
@@ -55,7 +62,7 @@ import org.springframework.context.annotation.Configuration;
 <%_ if (databaseType === 'mongodb' || databaseType === 'couchbase') { _%>
 import org.springframework.context.annotation.Import;
 <%_ } _%>
-<%_ if (searchEngine === 'elasticsearch' && databaseType === 'mongodb') { _%>
+<%_ if ((searchEngine === 'elasticsearch' || reactive) && databaseType === 'mongodb') { _%>
 import org.springframework.context.annotation.ComponentScan.Filter;
 import org.springframework.context.annotation.FilterType;
 <%_ } _%>
@@ -64,9 +71,6 @@ import org.springframework.context.annotation.Profile;<% } %><% if (databaseType
 import org.springframework.core.env.Environment;<% } %><% if (databaseType === 'mongodb' || databaseType === 'couchbase') { %>
 import org.springframework.core.convert.converter.Converter;<% } %>
 <%_ if (searchEngine === 'elasticsearch') { _%>
-    <%_ if (databaseType === 'mongodb') { _%>
-import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;
-    <%_ } _%>
 import org.springframework.data.elasticsearch.repository.config.EnableElasticsearchRepositories;
 <%_ } _%>
 <%_ if (databaseType === 'mongodb') { _%>
@@ -74,10 +78,15 @@ import org.springframework.data.mongodb.config.EnableMongoAuditing;
 import org.springframework.data.mongodb.core.MongoTemplate;
 import org.springframework.data.mongodb.core.convert.MongoCustomConversions;
 import org.springframework.data.mongodb.core.mapping.event.ValidatingMongoEventListener;
-    <%_ if (searchEngine === 'elasticsearch') { _%>
+    <%_ if (searchEngine === 'elasticsearch' || reactive) { _%>
 import org.springframework.data.mongodb.repository.MongoRepository;
     <%_ } _%>
-import org.springframework.data.mongodb.repository.config.EnableMongoRepositories;<% } %><% if (databaseType === 'couchbase') { %>
+import org.springframework.data.mongodb.repository.config.EnableMongoRepositories;
+    <%_ if (reactive) { _%>
+import org.springframework.data.mongodb.repository.config.EnableReactiveMongoRepositories;
+    <%_ } _%>
+<%_ } _%>
+<%_ if (databaseType === 'couchbase') { _%>
 import org.springframework.data.convert.ReadingConverter;
 import org.springframework.data.convert.WritingConverter;
 import org.springframework.data.couchbase.config.BeanNames;
@@ -85,6 +94,9 @@ import org.springframework.data.couchbase.core.convert.CouchbaseCustomConversion
 import org.springframework.data.couchbase.core.mapping.event.ValidatingCouchbaseEventListener;
 import org.springframework.data.couchbase.repository.auditing.EnableCouchbaseAuditing;
 import org.springframework.data.couchbase.repository.config.EnableCouchbaseRepositories;
+    <%_ if (reactive) { _%>
+import org.springframework.data.couchbase.repository.config.EnableReactiveCouchbaseRepositories;
+    <%_ } _%>
 import org.springframework.util.StringUtils;<% } %><% if (databaseType === 'mongodb' || databaseType === 'couchbase') { %>
 import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;<% } %>
 <%_ if (databaseType === 'sql') { _%>
@@ -113,29 +125,41 @@ import java.util.Date;
 import java.util.List;
 <%_ } _%>
 
-@Configuration<% if (databaseType === 'sql') { %>
+@Configuration
+<%_ if (databaseType === 'sql') { _%>
 @EnableJpaRepositories("<%=packageName%>.repository")
 @EnableJpaAuditing(auditorAwareRef = "springSecurityAuditorAware")
-@EnableTransactionManagement<% } %>
-<%_ if (searchEngine === 'elasticsearch' && databaseType === 'mongodb') { _%>
-@EnableElasticsearchRepositories(basePackages = "<%=packageName%>.repository.search", excludeFilters = @Filter(type = FilterType.ASSIGNABLE_TYPE, value = MongoRepository.class))
-@EnableMongoRepositories(basePackages = "<%=packageName%>.repository", excludeFilters = @Filter(type = FilterType.ASSIGNABLE_TYPE, value = ElasticsearchRepository.class))
+@EnableTransactionManagement
 <%_ } _%>
-<%_ if (searchEngine === 'elasticsearch' && databaseType != 'mongodb') { _%>
+<%_ if (searchEngine === 'elasticsearch') { _%>
 @EnableElasticsearchRepositories("<%=packageName%>.repository.search")
 <%_ } _%>
-<%_ if (searchEngine != 'elasticsearch' && databaseType === 'mongodb') { _%>
+<%_ if (databaseType === 'mongodb') { _%>
+    <%_ if (searchEngine === 'elasticsearch' || reactive) { _%>
+@EnableMongoRepositories(basePackages = "<%=packageName%>.repository", includeFilters = @Filter(type = FilterType.ASSIGNABLE_TYPE, value = MongoRepository.class))
+    <%_ } else { _%>
 @EnableMongoRepositories("<%=packageName%>.repository")
+    <%_ } _%>
+    <%_ if (reactive) { _%>
+@EnableReactiveMongoRepositories("<%=packageName%>.repository.reactive")
+    <%_ } _%>
 <%_ } _%>
 <%_ if (databaseType === 'mongodb' || databaseType === 'couchbase') { _%>
 @Profile("!" + JHipsterConstants.SPRING_PROFILE_CLOUD)
 <%_ } _%>
 <%_ if (databaseType === 'mongodb') { _%>
+    <%_ if (reactive) { _%>
+@Import(value = {MongoAutoConfiguration.class, MongoReactiveAutoConfiguration.class})
+    <%_ } else { _%>
 @Import(value = MongoAutoConfiguration.class)
+    <%_ } _%>
 @EnableMongoAuditing(auditorAwareRef = "springSecurityAuditorAware")
 <%_ } _%>
 <%_ if (databaseType === 'couchbase') { _%>
 @EnableCouchbaseRepositories(repositoryBaseClass = CustomN1qlCouchbaseRepository.class, basePackages = "<%=packageName%>.repository")
+    <%_ if (reactive) { _%>
+@EnableReactiveCouchbaseRepositories("<%=packageName%>.repository.reactive")
+    <%_ } _%>
 @Import(value = CouchbaseAutoConfiguration.class)
 @EnableCouchbaseAuditing(auditorAwareRef = "springSecurityAuditorAware")
 <%_ } _%>
diff --git a/generators/server/templates/src/main/java/package/config/cassandra/CassandraConfiguration.java.ejs b/generators/server/templates/src/main/java/package/config/cassandra/CassandraConfiguration.java.ejs
index e62d1d1606..678c4ae3ab 100644
--- a/generators/server/templates/src/main/java/package/config/cassandra/CassandraConfiguration.java.ejs
+++ b/generators/server/templates/src/main/java/package/config/cassandra/CassandraConfiguration.java.ejs
@@ -25,8 +25,10 @@ import org.slf4j.LoggerFactory;
 import org.springframework.beans.BeanUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Value;
-import org.springframework.boot.autoconfigure.cassandra.CassandraProperties;<% if (applicationType === 'gateway' && databaseType !== 'cassandra') { %>
-import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;<% } %>
+import org.springframework.boot.autoconfigure.cassandra.CassandraProperties;
+<%_ if (applicationType === 'gateway' && databaseType !== 'cassandra') { _%>
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+<%_ } _%>
 import org.springframework.boot.context.properties.EnableConfigurationProperties;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
diff --git a/generators/server/templates/src/main/java/package/domain/Authority.java.ejs b/generators/server/templates/src/main/java/package/domain/Authority.java.ejs
index f39ac20882..f789926e7b 100644
--- a/generators/server/templates/src/main/java/package/domain/Authority.java.ejs
+++ b/generators/server/templates/src/main/java/package/domain/Authority.java.ejs
@@ -52,10 +52,8 @@ import java.io.Serializable;
 <%_ } _%>
 <%_ if (databaseType === 'mongodb') { _%>
 @Document(collection = "<%= jhiTablePrefix %>_authority")
-<%_ } _%>
-<%_ if (databaseType === 'couchbase') { _%>
-@Document
-<%_ } _%>
+<%_ } _%><% if (databaseType === 'couchbase') { %>
+@Document<% } %>
 public class Authority implements Serializable {
 
     private static final long serialVersionUID = 1L;
diff --git a/generators/server/templates/src/main/java/package/repository/AuthorityRepository.java.ejs b/generators/server/templates/src/main/java/package/repository/AuthorityRepository.java.ejs
index 201b4abb35..d7e0a5889b 100644
--- a/generators/server/templates/src/main/java/package/repository/AuthorityRepository.java.ejs
+++ b/generators/server/templates/src/main/java/package/repository/AuthorityRepository.java.ejs
@@ -24,20 +24,12 @@ import org.springframework.data.jpa.repository.JpaRepository;<% } %><% if (datab
 
 import org.springframework.data.mongodb.repository.MongoRepository;<% } %>
 
-<%_ if (databaseType === 'sql') { _%>
-/**
+<% if (databaseType === 'sql') { %>/**
  * Spring Data JPA repository for the Authority entity.
- */
- <%_ } _%>
- <%_ if (databaseType === 'mongodb') { _%>
-/**
+ */<% } %><% if (databaseType === 'mongodb') { %>/**
  * Spring Data MongoDB repository for the Authority entity.
- */
-<%_ } _%>
-<%_ if (databaseType === 'couchbase') { _%>
-/**
+ */<% } %><% if (databaseType === 'couchbase') { %>/**
  * Spring Data Couchbase repository for the Authority entity.
- */
-<%_ } _%>
+ */<% } %>
 public interface AuthorityRepository extends <% if (databaseType === 'sql') { %>JpaRepository<% } %><% if (databaseType === 'mongodb') { %>MongoRepository<% } %><% if (databaseType === 'couchbase') { %>N1qlCouchbaseRepository<% } %><Authority, String> {
 }
diff --git a/generators/server/templates/src/main/java/package/service/UserService.java.ejs b/generators/server/templates/src/main/java/package/service/UserService.java.ejs
index 0382137fa8..b9beeb0577 100644
--- a/generators/server/templates/src/main/java/package/service/UserService.java.ejs
+++ b/generators/server/templates/src/main/java/package/service/UserService.java.ejs
@@ -512,22 +512,6 @@ public class UserService {
     }
 
     private User syncUserWithIdP(Map<String, Object> details, User user) {
-        // save authorities in to sync user roles/groups between IdP and JHipster's local database
-        Collection<String> dbAuthorities = getAuthorities();
-        <%_ if (databaseType !== 'couchbase') { _%>
-        Collection<String> userAuthorities =
-            user.getAuthorities().stream().map(Authority::getName).collect(Collectors.toList());
-        <%_ } else { _%>
-        Collection<String> userAuthorities = user.getAuthorities();
-        <%_ } _%>
-        for (String authority : userAuthorities) {
-            if (!dbAuthorities.contains(authority)) {
-                log.debug("Saving authority '{}' in local database", authority);
-                Authority authoritytoSave = new Authority();
-                authoritytoSave.setName(authority);
-                authorityRepository.save(authoritytoSave);
-            }
-        }
         // save account in to sync users between IdP and JHipster's local database
         Optional<User> existingUser = userRepository.findOneByLogin(user.getLogin());
         if (existingUser.isPresent()) {
@@ -536,18 +520,18 @@ public class UserService {
                 Instant dbModifiedDate = existingUser.get().getLastModifiedDate();
                 Instant idpModifiedDate = new Date(Long.valueOf((Integer) details.get("updated_at"))).toInstant();
                 if (idpModifiedDate.isAfter(dbModifiedDate)) {
-                    log.debug("Updating user '{}' in local database", user.getLogin());
+                    log.debug("Updating user '{}' in local database...", user.getLogin());
                     updateUser(user.getFirstName(), user.getLastName(), user.getEmail(),
                         user.getLangKey(), user.getImageUrl());
                 }
                 // no last updated info, blindly update
             } else {
-                log.debug("Updating user '{}' in local database", user.getLogin());
+                log.debug("Updating user '{}' in local database...", user.getLogin());
                 updateUser(user.getFirstName(), user.getLastName(), user.getEmail(),
                     user.getLangKey(), user.getImageUrl());
             }
         } else {
-            log.debug("Saving user '{}' in local database", user.getLogin());
+            log.debug("Saving user '{}' in local database...", user.getLogin());
             userRepository.save(user);
             <%_ if (cacheManagerIsAvailable === true) { _%>
             this.clearUserCaches(user);
diff --git a/travis/samples/.jhipster/CassBankAccount.json b/travis/samples/.jhipster/CassBankAccount.json
index e574a9ffae..f4cd2afdcf 100644
--- a/travis/samples/.jhipster/CassBankAccount.json
+++ b/travis/samples/.jhipster/CassBankAccount.json
@@ -58,7 +58,7 @@
     ],
     "changelogDate": "20150805124838",
     "dto": "mapstruct",
-    "service": "no",
+    "service": "serviceImpl",
     "angularJSSuffix": "mySuffix",
     "pagination": "no"
 }
diff --git a/travis/samples/.jhipster/DocumentBankAccount.json b/travis/samples/.jhipster/DocumentBankAccount.json
index 9dc7d1bf29..b27d07a353 100644
--- a/travis/samples/.jhipster/DocumentBankAccount.json
+++ b/travis/samples/.jhipster/DocumentBankAccount.json
@@ -61,6 +61,6 @@
     ],
     "changelogDate": "20150805124838",
     "dto": "mapstruct",
-    "service": "no",
+    "service": "serviceImpl",
     "pagination": "no"
 }
diff --git a/travis/samples/ngx-couchbase/.yo-rc.json b/travis/samples/ngx-couchbase/.yo-rc.json
index 38cecf3e7b..9ab1dd0995 100644
--- a/travis/samples/ngx-couchbase/.yo-rc.json
+++ b/travis/samples/ngx-couchbase/.yo-rc.json
@@ -11,6 +11,7 @@
       "databaseType": "couchbase",
       "devDatabaseType": "couchbase",
       "prodDatabaseType": "couchbase",
+      "reactive": true,
       "searchEngine": false,
       "messageBroker": false,
       "serviceDiscoveryType": false,
diff --git a/travis/samples/ngx-mongodb-kafka-cucumber/.yo-rc.json b/travis/samples/ngx-mongodb-kafka-cucumber/.yo-rc.json
index 9b4fa218a7..af1d2d1506 100644
--- a/travis/samples/ngx-mongodb-kafka-cucumber/.yo-rc.json
+++ b/travis/samples/ngx-mongodb-kafka-cucumber/.yo-rc.json
@@ -11,6 +11,7 @@
     "databaseType": "mongodb",
     "devDatabaseType": "mongodb",
     "prodDatabaseType": "mongodb",
+    "reactive": true,
     "searchEngine": false,
     "useSass": false,
     "buildTool": "maven",
diff --git a/travis/samples/ngx-session-cassandra-fr/.yo-rc.json b/travis/samples/ngx-session-cassandra-fr/.yo-rc.json
index 3c5ec94ac0..445bde55b2 100644
--- a/travis/samples/ngx-session-cassandra-fr/.yo-rc.json
+++ b/travis/samples/ngx-session-cassandra-fr/.yo-rc.json
@@ -11,6 +11,7 @@
     "databaseType": "cassandra",
     "devDatabaseType": "cassandra",
     "prodDatabaseType": "cassandra",
+    "reactive": true,
     "searchEngine": false,
     "useSass": false,
     "buildTool": "maven",


Test patch:
diff --git a/generators/client/templates/angular/webpack/webpack.test.js.ejs b/generators/client/templates/angular/webpack/webpack.test.js.ejs
index 8bb0cdc87e..4a25655cc2 100644
--- a/generators/client/templates/angular/webpack/webpack.test.js.ejs
+++ b/generators/client/templates/angular/webpack/webpack.test.js.ejs
@@ -69,13 +69,7 @@ module.exports = (WATCH) => ({
                 enforce: 'post',
                 exclude: /node_modules/,
                 loader: 'sourcemap-istanbul-instrumenter-loader?force-sourcemap=true'
-            },
-            // Ignore warnings about System.import in Angular
-            {
-                test: /[\/\\]@angular[\/\\].+\.js$/,
-                parser: { system: true }
-            },
-        ]
+            }]
     },
     plugins: [
         new webpack.DefinePlugin({
diff --git a/generators/entity-server/templates/src/test/java/package/web/rest/EntityResourceIntTest.java.ejs b/generators/entity-server/templates/src/test/java/package/web/rest/EntityResourceIntTest.java.ejs
index 2a49637e30..c80f903d16 100644
--- a/generators/entity-server/templates/src/test/java/package/web/rest/EntityResourceIntTest.java.ejs
+++ b/generators/entity-server/templates/src/test/java/package/web/rest/EntityResourceIntTest.java.ejs
@@ -30,11 +30,19 @@ import <%=packageName%>.domain.<%= entityClass %>;
         if ((relationshipValidate !== null && relationshipValidate === true) || jpaMetamodelFiltering) { _%>
 import <%=packageName%>.domain.<%= otherEntityNameCapitalized %>;
 <%_ } } _%>
-import <%=packageName%>.repository.<%= entityClass %>Repository;<% if (service !== 'no') { %>
-import <%=packageName%>.service.<%= entityClass %>Service;<% } if (searchEngine === 'elasticsearch') { %>
-import <%=packageName%>.repository.search.<%= entityClass %>SearchRepository;<% } if (dto === 'mapstruct') { %>
+import <%=packageName%>.repository.<%= entityClass %>Repository;
+<%_ if (searchEngine === 'elasticsearch') { _%>
+import <%=packageName%>.repository.search.<%= entityClass %>SearchRepository;
+<%_ } _%>
+<%_ if (service !== 'no') { _%>
+import <%=packageName%>.service.<%= entityClass %>Service;
+<%_ } else if (reactiveRepositories) { _%>
+import <%=packageName%>.repository.reactive.<%= entityClass %>ReactiveRepository;
+<%_ } _%>
+<%_ if (dto === 'mapstruct') { _%>
 import <%=packageName%>.service.dto.<%= entityClass %>DTO;
-import <%=packageName%>.service.mapper.<%= entityClass %>Mapper;<% } %>
+import <%=packageName%>.service.mapper.<%= entityClass %>Mapper;
+<%_ } _%>
 import <%=packageName%>.web.rest.errors.ExceptionTranslator;
 <%_ if (jpaMetamodelFiltering) { _%>
 import <%=packageName%>.service.dto.<%= entityClass %>Criteria;
@@ -56,6 +64,9 @@ import org.springframework.data.web.PageableHandlerMethodArgumentResolver;
 import org.springframework.http.MediaType;
 import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
 import org.springframework.test.context.junit4.SpringRunner;
+<%_ if (reactiveRepositories) { _%>
+import org.springframework.test.web.reactive.server.WebTestClient;
+<%_ } _%>
 import org.springframework.test.web.servlet.MockMvc;
 import org.springframework.test.web.servlet.setup.MockMvcBuilders;<% if (databaseType === 'sql') { %>
 import org.springframework.transaction.annotation.Transactional;<% } %><% if (fieldsContainBlob === true) { %>
@@ -63,7 +74,8 @@ import org.springframework.util.Base64Utils;<% } %>
 <% if (databaseType === 'sql') { %>
 import javax.persistence.EntityManager;<% } %><% if (fieldsContainBigDecimal === true) { %>
 import java.math.BigDecimal;<% } %><% if (fieldsContainBlob === true && databaseType === 'cassandra') { %>
-import java.nio.ByteBuffer;<% } %><% if (fieldsContainLocalDate === true) { %>
+import java.nio.ByteBuffer;<% } %><% if (reactiveRepositories) { %>
+import java.time.Duration;<% } %><% if (fieldsContainLocalDate === true) { %>
 import java.time.LocalDate;<% } %><% if (fieldsContainInstant === true || fieldsContainZonedDateTime === true) { %>
 import java.time.Instant;<% } %><% if (fieldsContainZonedDateTime === true) { %>
 import java.time.ZonedDateTime;
@@ -267,6 +279,11 @@ _%>
     @Autowired
     private <%= entityClass %>Repository <%= entityInstance %>Repository;
 
+    <%_ if (reactiveRepositories && service === 'no') { _%>
+    @Autowired
+    private <%= entityClass %>ReactiveRepository <%= entityInstance %>ReactiveRepository;
+
+    <%_ } _%>
     <%_ if (fieldsContainOwnerManyToMany === true) { _%>
     @Mock
     private <%= entityClass %>Repository <%= entityInstance %>RepositoryMock;<%_ } _%><% if (dto === 'mapstruct') { %>
@@ -317,7 +334,7 @@ _%>
         <%_ if (service !== 'no') { _%>
         final <%= entityClass %>Resource <%= entityInstance %>Resource = new <%= entityClass %>Resource(<%= entityInstance %>Service<% if (jpaMetamodelFiltering) { %>, <%= entityInstance %>QueryService<% } %>);
         <%_ } else { _%>
-        final <%= entityClass %>Resource <%= entityInstance %>Resource = new <%= entityClass %>Resource(<%= entityInstance %>Repository<% if (dto === 'mapstruct') { %>, <%= entityInstance %>Mapper<% } %><% if (searchEngine === 'elasticsearch') { %>, mock<%= entityClass %>SearchRepository<% } %><% if (jpaMetamodelFiltering) { %>, <%= entityInstance %>QueryService<% } %>);
+        final <%= entityClass %>Resource <%= entityInstance %>Resource = new <%= entityClass %>Resource(<%= entityInstance %>Repository<% if (dto === 'mapstruct') { %>, <%= entityInstance %>Mapper<% } %><% if (searchEngine === 'elasticsearch') { %>, mock<%= entityClass %>SearchRepository<% } %><% if (reactiveRepositories) { %>, <%= entityInstance %>ReactiveRepository<% } %><% if (jpaMetamodelFiltering) { %>, <%= entityInstance %>QueryService<% } %>);
         <%_ } _%>
         this.rest<%= entityClass %>MockMvc = MockMvcBuilders.standaloneSetup(<%= entityInstance %>Resource)
             .setCustomArgumentResolvers(pageableArgumentResolver)
@@ -688,7 +705,48 @@ _%>
     }
 
 <%_  } _%>
+<%_ if (reactiveRepositories) { _%>
+
+    @Test
+    public void getAll<%= entityClassPlural %>AsStream() {
+        // Initialize the database
+        <%= entityInstance %>Repository.save(<%= entityInstance %>);
+
+        <%_ if (service !== 'no') { _%>
+        final <%= entityClass %>Resource <%= entityInstance %>Resource = new <%= entityClass %>Resource(<%= entityInstance %>Service<% if (jpaMetamodelFiltering) { %>, <%= entityInstance %>QueryService<% } %>);
+        <%_ } else { _%>
+        final <%= entityClass %>Resource <%= entityInstance %>Resource = new <%= entityClass %>Resource(<%= entityInstance %>Repository<% if (dto === 'mapstruct') { %>, <%= entityInstance %>Mapper<% } %><% if (searchEngine === 'elasticsearch') { %>, mock<%= entityClass %>SearchRepository<% } %><% if (reactiveRepositories) { %>, <%= entityInstance %>ReactiveRepository<% } %><% if (jpaMetamodelFiltering) { %>, <%= entityInstance %>QueryService<% } %>);
+        <%_ } _%>
+        WebTestClient client = WebTestClient.bindToController(<%= entityInstance %>Resource).build();
+
+        List<<%= entityClass %>> <%= entityInstance %>List = client.get().uri("/api/<%= entityApiUrl %>").accept(MediaType.APPLICATION_STREAM_JSON).exchange()
+            .expectStatus().isOk()
+            .expectHeader().contentTypeCompatibleWith(MediaType.APPLICATION_STREAM_JSON)
+            .returnResult(<%= entityClass %><% if (dto !== 'no') { %>DTO<% } %>.class)
+            .getResponseBody()
+            <%_ if (dto !== 'no') { _%>
+            .map(<%= entityInstance %>Mapper::toEntity)
+            <%_ } _%>
+            .filter(<%= entityInstance %>::equals)
+            .collectList()
+            .block(Duration.ofSeconds(5));
+
+        assertThat(<%= entityInstance %>List).isNotNull();
+        assertThat(<%= entityInstance %>List).hasSize(1);
+        <%= entityClass %> test<%= entityClass %> = <%= entityInstance %>List.get(0);
+        <%_ for (idx in fields) { if (fields[idx].fieldType === 'ZonedDateTime') { _%>
+        assertThat(test<%= entityClass %>.get<%=fields[idx].fieldInJavaBeanMethod%>()).isEqualTo(<%='DEFAULT_' + fields[idx].fieldNameUnderscored.toUpperCase()%>);
+        <%_ } else if ((fields[idx].fieldType === 'byte[]' || fields[idx].fieldType === 'ByteBuffer') && fields[idx].fieldTypeBlobContent !== 'text') { _%>
+        assertThat(test<%= entityClass %>.get<%=fields[idx].fieldInJavaBeanMethod%>()).isEqualTo(<%='DEFAULT_' + fields[idx].fieldNameUnderscored.toUpperCase()%>);
+        assertThat(test<%= entityClass %>.get<%=fields[idx].fieldInJavaBeanMethod%>ContentType()).isEqualTo(<%='DEFAULT_' + fields[idx].fieldNameUnderscored.toUpperCase()%>_CONTENT_TYPE);
+        <%_ } else if (fields[idx].fieldType.toLowerCase() === 'boolean') { _%>
+        assertThat(test<%= entityClass %>.is<%=fields[idx].fieldInJavaBeanMethod%>()).isEqualTo(<%='DEFAULT_' + fields[idx].fieldNameUnderscored.toUpperCase()%>);
+        <%_ } else { _%>
+        assertThat(test<%= entityClass %>.get<%=fields[idx].fieldInJavaBeanMethod%>()).isEqualTo(<%='DEFAULT_' + fields[idx].fieldNameUnderscored.toUpperCase()%>);
+        <%_ }} _%>
+    }
 
+    <%_  } _%>
     @Test<% if (databaseType === 'sql') { %>
     @Transactional<% } %>
     public void getNonExisting<%= entityClass %>() throws Exception {
diff --git a/travis/samples/.jhipster/CassTestMapstructEntity.json b/travis/samples/.jhipster/CassTestMapstructEntity.json
index dbfd7d5cb2..bac2818d95 100644
--- a/travis/samples/.jhipster/CassTestMapstructEntity.json
+++ b/travis/samples/.jhipster/CassTestMapstructEntity.json
@@ -213,6 +213,6 @@
     ],
     "changelogDate": "20160208184031",
     "dto": "mapstruct",
-    "service": "no",
+    "service": "serviceImpl",
     "pagination": "no"
 }
diff --git a/travis/samples/.jhipster/FieldTestMapstructEntity.json b/travis/samples/.jhipster/FieldTestMapstructEntity.json
index 970bead1cc..6fd3a8e189 100644
--- a/travis/samples/.jhipster/FieldTestMapstructEntity.json
+++ b/travis/samples/.jhipster/FieldTestMapstructEntity.json
@@ -318,6 +318,6 @@
     ],
     "changelogDate": "20160208184031",
     "dto": "mapstruct",
-    "service": "no",
+    "service": "serviceClass",
     "pagination": "no"
 }