From e17d68441eada46e0ee024a9b230449f2b4ba3a9 Mon Sep 17 00:00:00 2001 From: Puneet Behl Date: Tue, 26 May 2020 16:35:56 +0530 Subject: [PATCH 01/11] #202 Test that GORM data service is initialized --- build.gradle | 2 +- examples/test-data-service/build.gradle | 44 +++++++ .../grails-app/conf/application.groovy | 14 +++ .../grails-app/conf/application.yml | 116 ++++++++++++++++++ .../grails-app/conf/logback.groovy | 37 ++++++ .../grails-app/conf/spring/resources.groovy | 9 ++ .../example/ApplicationController.groovy | 14 +++ .../controllers/example/UrlMappings.groovy | 17 +++ .../grails-app/domain/example/Book.groovy | 5 + .../grails-app/i18n/messages.properties | 56 +++++++++ .../init/example/Application.groovy | 13 ++ .../grails-app/init/example/BootStrap.groovy | 9 ++ .../services/example/BookService.groovy | 9 ++ .../services/example/LibraryService.groovy | 14 +++ .../services/example/TestService.groovy | 10 ++ .../grails-app/views/application/index.gson | 33 +++++ .../grails-app/views/error.gson | 6 + .../grails-app/views/errors/_errors.gson | 42 +++++++ .../grails-app/views/notFound.gson | 6 + .../grails-app/views/object/_object.gson | 5 + .../groovy/example/TestServiceSpec.groovy | 20 +++ .../LoginAuthenticationSucessHandler.groovy | 21 ++++ settings.gradle | 4 + 23 files changed, 505 insertions(+), 1 deletion(-) create mode 100644 examples/test-data-service/build.gradle create mode 100644 examples/test-data-service/grails-app/conf/application.groovy create mode 100644 examples/test-data-service/grails-app/conf/application.yml create mode 100644 examples/test-data-service/grails-app/conf/logback.groovy create mode 100644 examples/test-data-service/grails-app/conf/spring/resources.groovy create mode 100644 examples/test-data-service/grails-app/controllers/example/ApplicationController.groovy create mode 100644 examples/test-data-service/grails-app/controllers/example/UrlMappings.groovy create mode 100644 examples/test-data-service/grails-app/domain/example/Book.groovy create mode 100644 examples/test-data-service/grails-app/i18n/messages.properties create mode 100644 examples/test-data-service/grails-app/init/example/Application.groovy create mode 100644 examples/test-data-service/grails-app/init/example/BootStrap.groovy create mode 100644 examples/test-data-service/grails-app/services/example/BookService.groovy create mode 100644 examples/test-data-service/grails-app/services/example/LibraryService.groovy create mode 100644 examples/test-data-service/grails-app/services/example/TestService.groovy create mode 100644 examples/test-data-service/grails-app/views/application/index.gson create mode 100644 examples/test-data-service/grails-app/views/error.gson create mode 100644 examples/test-data-service/grails-app/views/errors/_errors.gson create mode 100644 examples/test-data-service/grails-app/views/notFound.gson create mode 100644 examples/test-data-service/grails-app/views/object/_object.gson create mode 100644 examples/test-data-service/src/integration-test/groovy/example/TestServiceSpec.groovy create mode 100644 examples/test-data-service/src/main/groovy/example/LoginAuthenticationSucessHandler.groovy diff --git a/build.gradle b/build.gradle index 0acde2a244..5c973433c1 100644 --- a/build.gradle +++ b/build.gradle @@ -4,7 +4,6 @@ import static groovyx.net.http.ContentType.JSON buildscript { repositories { - mavenLocal() maven { url "https://repo.grails.org/grails/core" } } dependencies { @@ -14,6 +13,7 @@ buildscript { // classpath "io.codearte.gradle.nexus:gradle-nexus-staging-plugin:0.5.3" classpath "io.github.groovylang.groovydoc:groovydoc-gradle-plugin:1.0.1" classpath "org.grails:grails-gradle-plugin:$grailsVersion" + classpath "org.grails.plugins:views-gradle:2.0.0" classpath 'org.asciidoctor:asciidoctor-gradle-plugin:1.5.9.2' classpath "gradle.plugin.com.energizedwork.webdriver-binaries:webdriver-binaries-gradle-plugin:$webdriverBinariesVersion" } diff --git a/examples/test-data-service/build.gradle b/examples/test-data-service/build.gradle new file mode 100644 index 0000000000..7e60cce9e9 --- /dev/null +++ b/examples/test-data-service/build.gradle @@ -0,0 +1,44 @@ +group "examples" + +apply plugin:"org.grails.grails-web" +apply plugin:"org.grails.plugins.views-json" + +configurations.all { + resolutionStrategy.eachDependency { DependencyResolveDetails details -> + if(details.requested.group == 'org.grails' && + details.requested.name.startsWith('grails-datastore') && + details.requested.name != 'grails-datastore-gorm-hibernate5') { + details.useVersion(gormVersion) + } + } +} + +dependencies { + compile "org.springframework.boot:spring-boot-starter-logging" + compile "org.springframework.boot:spring-boot-autoconfigure" + compile "org.grails:grails-core" + compile "org.springframework.boot:spring-boot-starter-actuator" + compile "org.springframework.boot:spring-boot-starter-tomcat" + compile "org.grails:grails-dependencies" + compile "org.grails:grails-plugin-codecs" + compile "org.grails:grails-plugin-services" + compile "org.grails:grails-plugin-datasource" + compile "org.grails:grails-web-boot" + compile "org.grails:grails-logging" + compile "org.grails.plugins:cache" + compile "org.grails.plugins:events" + compile project(":grails-plugin") + compile "org.hibernate:hibernate-core:$hibernate5Version" + compile "org.grails.plugins:views-json" + compile "org.grails.plugins:views-json-templates" + compile 'org.grails.plugins:spring-security-rest:3.0.1' + compileOnly "io.micronaut:micronaut-inject-groovy" + console "org.grails:grails-console" + profile "org.grails.profiles:rest-api" + runtime "org.glassfish.web:el-impl:2.1.2-b03" + runtime "org.apache.tomcat:tomcat-jdbc" + runtime "javax.xml.bind:jaxb-api:2.3.0" + testCompile "org.grails:grails-gorm-testing-support" + testCompile "io.micronaut:micronaut-http-client" + testCompile "org.grails:grails-web-testing-support" +} diff --git a/examples/test-data-service/grails-app/conf/application.groovy b/examples/test-data-service/grails-app/conf/application.groovy new file mode 100644 index 0000000000..3f36c438d0 --- /dev/null +++ b/examples/test-data-service/grails-app/conf/application.groovy @@ -0,0 +1,14 @@ +grails.plugin.springsecurity.rest.token.storage.jwt.secret = "anystoragejwtsecretwithalargevalue" +grails.plugin.springsecurity.filterChain.chainMap = [ + //Stateless chain + [ + pattern: '/**', + filters: 'JOINED_FILTERS,-anonymousAuthenticationFilter,-exceptionTranslationFilter,-authenticationProcessingFilter,-securityContextPersistenceFilter,-rememberMeAuthenticationFilter' + ], + + //Traditional, stateful chain + [ + pattern: '/stateful/**', + filters: 'JOINED_FILTERS,-restTokenValidationFilter,-restExceptionTranslationFilter' + ] +] diff --git a/examples/test-data-service/grails-app/conf/application.yml b/examples/test-data-service/grails-app/conf/application.yml new file mode 100644 index 0000000000..48116b8d4b --- /dev/null +++ b/examples/test-data-service/grails-app/conf/application.yml @@ -0,0 +1,116 @@ +--- +grails: + profile: rest-api + codegen: + defaultPackage: example + gorm: + reactor: + # Whether to translate GORM events into Reactor events + # Disabled by default for performance reasons + events: false +info: + app: + name: '@info.app.name@' + version: '@info.app.version@' + grailsVersion: '@info.app.grailsVersion@' +spring: + jmx: + unique-names: true + main: + banner-mode: "off" + groovy: + template: + check-template-location: false + devtools: + restart: + additional-exclude: + - '*.gsp' + - '**/*.gsp' + - '*.gson' + - '**/*.gson' + - 'logback.groovy' + - '*.properties' +management: + endpoints: + enabled-by-default: false + +--- +grails: + mime: + disable: + accept: + header: + userAgents: + - Gecko + - WebKit + - Presto + - Trident + types: + json: + - application/json + - text/json + hal: + - application/hal+json + - application/hal+xml + xml: + - text/xml + - application/xml + atom: application/atom+xml + css: text/css + csv: text/csv + js: text/javascript + rss: application/rss+xml + text: text/plain + all: '*/*' + urlmapping: + cache: + maxsize: 1000 + controllers: + defaultScope: singleton + converters: + encoding: UTF-8 + +--- +hibernate: + cache: + queries: false + use_second_level_cache: false + use_query_cache: false +dataSource: + pooled: true + jmxExport: true + driverClassName: org.h2.Driver + username: sa + password: '' + +environments: + development: + dataSource: + dbCreate: create-drop + url: jdbc:h2:mem:devDb;MVCC=TRUE;LOCK_TIMEOUT=10000;DB_CLOSE_ON_EXIT=FALSE + test: + dataSource: + dbCreate: update + url: jdbc:h2:mem:testDb;MVCC=TRUE;LOCK_TIMEOUT=10000;DB_CLOSE_ON_EXIT=FALSE + production: + dataSource: + dbCreate: none + url: jdbc:h2:./prodDb;MVCC=TRUE;LOCK_TIMEOUT=10000;DB_CLOSE_ON_EXIT=FALSE + properties: + jmxEnabled: true + initialSize: 5 + maxActive: 50 + minIdle: 5 + maxIdle: 25 + maxWait: 10000 + maxAge: 600000 + timeBetweenEvictionRunsMillis: 5000 + minEvictableIdleTimeMillis: 60000 + validationQuery: SELECT 1 + validationQueryTimeout: 3 + validationInterval: 15000 + testOnBorrow: true + testWhileIdle: true + testOnReturn: false + jdbcInterceptors: ConnectionState + defaultTransactionIsolation: 2 # TRANSACTION_READ_COMMITTED diff --git a/examples/test-data-service/grails-app/conf/logback.groovy b/examples/test-data-service/grails-app/conf/logback.groovy new file mode 100644 index 0000000000..b835215c1e --- /dev/null +++ b/examples/test-data-service/grails-app/conf/logback.groovy @@ -0,0 +1,37 @@ +import grails.util.BuildSettings +import grails.util.Environment +import org.springframework.boot.logging.logback.ColorConverter +import org.springframework.boot.logging.logback.WhitespaceThrowableProxyConverter + +import java.nio.charset.StandardCharsets + +conversionRule 'clr', ColorConverter +conversionRule 'wex', WhitespaceThrowableProxyConverter + +// See http://logback.qos.ch/manual/groovy.html for details on configuration +appender('STDOUT', ConsoleAppender) { + encoder(PatternLayoutEncoder) { + charset = StandardCharsets.UTF_8 + + pattern = + '%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} ' + // Date + '%clr(%5p) ' + // Log level + '%clr(---){faint} %clr([%15.15t]){faint} ' + // Thread + '%clr(%-40.40logger{39}){cyan} %clr(:){faint} ' + // Logger + '%m%n%wex' // Message + } +} + +def targetDir = BuildSettings.TARGET_DIR +if (Environment.isDevelopmentMode() && targetDir != null) { + appender("FULL_STACKTRACE", FileAppender) { + file = "${targetDir}/stacktrace.log" + append = true + encoder(PatternLayoutEncoder) { + charset = StandardCharsets.UTF_8 + pattern = "%level %logger - %msg%n" + } + } + logger("StackTrace", ERROR, ['FULL_STACKTRACE'], false) +} +root(ERROR, ['STDOUT']) diff --git a/examples/test-data-service/grails-app/conf/spring/resources.groovy b/examples/test-data-service/grails-app/conf/spring/resources.groovy new file mode 100644 index 0000000000..2528520272 --- /dev/null +++ b/examples/test-data-service/grails-app/conf/spring/resources.groovy @@ -0,0 +1,9 @@ +import example.LoginAuthenticationSucessHandler + +// Place your Spring DSL code here +beans = { + + restAuthenticationSuccessHandler(LoginAuthenticationSucessHandler) { + testService = ref('testService') + } +} diff --git a/examples/test-data-service/grails-app/controllers/example/ApplicationController.groovy b/examples/test-data-service/grails-app/controllers/example/ApplicationController.groovy new file mode 100644 index 0000000000..0ea5d1ada3 --- /dev/null +++ b/examples/test-data-service/grails-app/controllers/example/ApplicationController.groovy @@ -0,0 +1,14 @@ +package example + +import grails.core.GrailsApplication +import grails.plugins.* + +class ApplicationController implements PluginManagerAware { + + GrailsApplication grailsApplication + GrailsPluginManager pluginManager + + def index() { + [grailsApplication: grailsApplication, pluginManager: pluginManager] + } +} diff --git a/examples/test-data-service/grails-app/controllers/example/UrlMappings.groovy b/examples/test-data-service/grails-app/controllers/example/UrlMappings.groovy new file mode 100644 index 0000000000..04cf3cce21 --- /dev/null +++ b/examples/test-data-service/grails-app/controllers/example/UrlMappings.groovy @@ -0,0 +1,17 @@ +package example + +class UrlMappings { + + static mappings = { + delete "/$controller/$id(.$format)?"(action:"delete") + get "/$controller(.$format)?"(action:"index") + get "/$controller/$id(.$format)?"(action:"show") + post "/$controller(.$format)?"(action:"save") + put "/$controller/$id(.$format)?"(action:"update") + patch "/$controller/$id(.$format)?"(action:"patch") + + "/"(controller: 'application', action:'index') + "500"(view: '/error') + "404"(view: '/notFound') + } +} diff --git a/examples/test-data-service/grails-app/domain/example/Book.groovy b/examples/test-data-service/grails-app/domain/example/Book.groovy new file mode 100644 index 0000000000..a3b450b787 --- /dev/null +++ b/examples/test-data-service/grails-app/domain/example/Book.groovy @@ -0,0 +1,5 @@ +package example + +class Book { + String title +} diff --git a/examples/test-data-service/grails-app/i18n/messages.properties b/examples/test-data-service/grails-app/i18n/messages.properties new file mode 100644 index 0000000000..b045136211 --- /dev/null +++ b/examples/test-data-service/grails-app/i18n/messages.properties @@ -0,0 +1,56 @@ +default.doesnt.match.message=Property [{0}] of class [{1}] with value [{2}] does not match the required pattern [{3}] +default.invalid.url.message=Property [{0}] of class [{1}] with value [{2}] is not a valid URL +default.invalid.creditCard.message=Property [{0}] of class [{1}] with value [{2}] is not a valid credit card number +default.invalid.email.message=Property [{0}] of class [{1}] with value [{2}] is not a valid e-mail address +default.invalid.range.message=Property [{0}] of class [{1}] with value [{2}] does not fall within the valid range from [{3}] to [{4}] +default.invalid.size.message=Property [{0}] of class [{1}] with value [{2}] does not fall within the valid size range from [{3}] to [{4}] +default.invalid.max.message=Property [{0}] of class [{1}] with value [{2}] exceeds maximum value [{3}] +default.invalid.min.message=Property [{0}] of class [{1}] with value [{2}] is less than minimum value [{3}] +default.invalid.max.size.message=Property [{0}] of class [{1}] with value [{2}] exceeds the maximum size of [{3}] +default.invalid.min.size.message=Property [{0}] of class [{1}] with value [{2}] is less than the minimum size of [{3}] +default.invalid.validator.message=Property [{0}] of class [{1}] with value [{2}] does not pass custom validation +default.not.inlist.message=Property [{0}] of class [{1}] with value [{2}] is not contained within the list [{3}] +default.blank.message=Property [{0}] of class [{1}] cannot be blank +default.not.equal.message=Property [{0}] of class [{1}] with value [{2}] cannot equal [{3}] +default.null.message=Property [{0}] of class [{1}] cannot be null +default.not.unique.message=Property [{0}] of class [{1}] with value [{2}] must be unique + +default.paginate.prev=Previous +default.paginate.next=Next +default.boolean.true=True +default.boolean.false=False +default.date.format=yyyy-MM-dd HH:mm:ss z +default.number.format=0 + +default.created.message={0} {1} created +default.updated.message={0} {1} updated +default.deleted.message={0} {1} deleted +default.not.deleted.message={0} {1} could not be deleted +default.not.found.message={0} not found with id {1} +default.optimistic.locking.failure=Another user has updated this {0} while you were editing + +default.home.label=Home +default.list.label={0} List +default.add.label=Add {0} +default.new.label=New {0} +default.create.label=Create {0} +default.show.label=Show {0} +default.edit.label=Edit {0} + +default.button.create.label=Create +default.button.edit.label=Edit +default.button.update.label=Update +default.button.delete.label=Delete +default.button.delete.confirm.message=Are you sure? + +# Data binding errors. Use "typeMismatch.$className.$propertyName to customize (eg typeMismatch.Book.author) +typeMismatch.java.net.URL=Property {0} must be a valid URL +typeMismatch.java.net.URI=Property {0} must be a valid URI +typeMismatch.java.util.Date=Property {0} must be a valid Date +typeMismatch.java.lang.Double=Property {0} must be a valid number +typeMismatch.java.lang.Integer=Property {0} must be a valid number +typeMismatch.java.lang.Long=Property {0} must be a valid number +typeMismatch.java.lang.Short=Property {0} must be a valid number +typeMismatch.java.math.BigDecimal=Property {0} must be a valid number +typeMismatch.java.math.BigInteger=Property {0} must be a valid number +typeMismatch=Property {0} is type-mismatched diff --git a/examples/test-data-service/grails-app/init/example/Application.groovy b/examples/test-data-service/grails-app/init/example/Application.groovy new file mode 100644 index 0000000000..0396c4b8c9 --- /dev/null +++ b/examples/test-data-service/grails-app/init/example/Application.groovy @@ -0,0 +1,13 @@ +package example + +import grails.boot.GrailsApp +import grails.boot.config.GrailsAutoConfiguration + +import groovy.transform.CompileStatic + +@CompileStatic +class Application extends GrailsAutoConfiguration { + static void main(String[] args) { + GrailsApp.run(Application, args) + } +} \ No newline at end of file diff --git a/examples/test-data-service/grails-app/init/example/BootStrap.groovy b/examples/test-data-service/grails-app/init/example/BootStrap.groovy new file mode 100644 index 0000000000..72406d5c9d --- /dev/null +++ b/examples/test-data-service/grails-app/init/example/BootStrap.groovy @@ -0,0 +1,9 @@ +package example + +class BootStrap { + + def init = { servletContext -> + } + def destroy = { + } +} diff --git a/examples/test-data-service/grails-app/services/example/BookService.groovy b/examples/test-data-service/grails-app/services/example/BookService.groovy new file mode 100644 index 0000000000..5b6a0eb728 --- /dev/null +++ b/examples/test-data-service/grails-app/services/example/BookService.groovy @@ -0,0 +1,9 @@ +package example + +import grails.gorm.services.Service + +@Service(Book) +interface BookService { + + Book get(Serializable id) +} diff --git a/examples/test-data-service/grails-app/services/example/LibraryService.groovy b/examples/test-data-service/grails-app/services/example/LibraryService.groovy new file mode 100644 index 0000000000..1e6c0eb3ea --- /dev/null +++ b/examples/test-data-service/grails-app/services/example/LibraryService.groovy @@ -0,0 +1,14 @@ +package example + +import grails.gorm.transactions.Transactional + +@Transactional +class LibraryService { + + BookService bookService + + Boolean bookExists(Serializable id) { + assert bookService != null + bookService.get(id) + } +} diff --git a/examples/test-data-service/grails-app/services/example/TestService.groovy b/examples/test-data-service/grails-app/services/example/TestService.groovy new file mode 100644 index 0000000000..99e7a54963 --- /dev/null +++ b/examples/test-data-service/grails-app/services/example/TestService.groovy @@ -0,0 +1,10 @@ +package example + +class TestService { + + LibraryService libraryService + + Boolean testDataService(Serializable id) { + libraryService.bookExists(id) + } +} diff --git a/examples/test-data-service/grails-app/views/application/index.gson b/examples/test-data-service/grails-app/views/application/index.gson new file mode 100644 index 0000000000..61f96439a8 --- /dev/null +++ b/examples/test-data-service/grails-app/views/application/index.gson @@ -0,0 +1,33 @@ +import grails.core.* +import grails.util.* +import grails.plugins.* +import org.grails.core.artefact.* + +model { + GrailsApplication grailsApplication + GrailsPluginManager pluginManager +} + +json { + message "Welcome to Grails!" + environment Environment.current.name + appversion grailsApplication.metadata.getApplicationVersion() + grailsversion GrailsUtil.grailsVersion + appprofile grailsApplication.config.getProperty('grails.profile') + groovyversion GroovySystem.getVersion() + jvmversion System.getProperty('java.version') + reloadingagentenabled Environment.reloadingAgentEnabled + artefacts ( + controllers: grailsApplication.getArtefactInfo(ControllerArtefactHandler.TYPE).classesByName.size(), + domains: grailsApplication.getArtefactInfo(DomainClassArtefactHandler.TYPE).classesByName.size(), + services: grailsApplication.getArtefactInfo(ServiceArtefactHandler.TYPE).classesByName.size() + ) + controllers grailsApplication.getArtefacts(ControllerArtefactHandler.TYPE), { GrailsClass c -> + name c.fullName + logicalPropertyName c.logicalPropertyName + } + plugins pluginManager.allPlugins, { GrailsPlugin plugin -> + name plugin.name + version plugin.version + } +} diff --git a/examples/test-data-service/grails-app/views/error.gson b/examples/test-data-service/grails-app/views/error.gson new file mode 100644 index 0000000000..94488283e6 --- /dev/null +++ b/examples/test-data-service/grails-app/views/error.gson @@ -0,0 +1,6 @@ +response.status 500 + +json { + message "Internal server error" + error 500 +} \ No newline at end of file diff --git a/examples/test-data-service/grails-app/views/errors/_errors.gson b/examples/test-data-service/grails-app/views/errors/_errors.gson new file mode 100644 index 0000000000..c1ae732d37 --- /dev/null +++ b/examples/test-data-service/grails-app/views/errors/_errors.gson @@ -0,0 +1,42 @@ +import org.springframework.validation.* + +/** + * Renders validation errors according to vnd.error: https://github.com/blongden/vnd.error + */ +model { + Errors errors +} + +response.status UNPROCESSABLE_ENTITY + +json { + Errors errorsObject = (Errors)this.errors + def allErrors = errorsObject.allErrors + int errorCount = allErrors.size() + def resourcePath = g.link(resource:request.uri, absolute:false) + def resourceLink = g.link(resource:request.uri, absolute:true) + if(errorCount == 1) { + def error = allErrors.iterator().next() + message messageSource.getMessage(error, locale) + path resourcePath + _links { + self { + href resourceLink + } + } + } + else { + total errorCount + _embedded { + errors(allErrors) { ObjectError error -> + message messageSource.getMessage(error, locale) + path resourcePath + _links { + self { + href resourceLink + } + } + } + } + } +} diff --git a/examples/test-data-service/grails-app/views/notFound.gson b/examples/test-data-service/grails-app/views/notFound.gson new file mode 100644 index 0000000000..1a710b2671 --- /dev/null +++ b/examples/test-data-service/grails-app/views/notFound.gson @@ -0,0 +1,6 @@ +response.status 404 + +json { + message "Not Found" + error 404 +} \ No newline at end of file diff --git a/examples/test-data-service/grails-app/views/object/_object.gson b/examples/test-data-service/grails-app/views/object/_object.gson new file mode 100644 index 0000000000..114568f77c --- /dev/null +++ b/examples/test-data-service/grails-app/views/object/_object.gson @@ -0,0 +1,5 @@ +import groovy.transform.* + +@Field Object object + +json g.render(object) diff --git a/examples/test-data-service/src/integration-test/groovy/example/TestServiceSpec.groovy b/examples/test-data-service/src/integration-test/groovy/example/TestServiceSpec.groovy new file mode 100644 index 0000000000..eb506879a0 --- /dev/null +++ b/examples/test-data-service/src/integration-test/groovy/example/TestServiceSpec.groovy @@ -0,0 +1,20 @@ +package example + +import grails.gorm.transactions.Rollback +import grails.testing.mixin.integration.Integration +import spock.lang.Specification + +@Integration +@Rollback +class TestServiceSpec extends Specification { + + TestService testService + + void "test data-service is loaded correctly"() { + when: + testService.testDataService() + + then: + noExceptionThrown() + } +} diff --git a/examples/test-data-service/src/main/groovy/example/LoginAuthenticationSucessHandler.groovy b/examples/test-data-service/src/main/groovy/example/LoginAuthenticationSucessHandler.groovy new file mode 100644 index 0000000000..266dfee512 --- /dev/null +++ b/examples/test-data-service/src/main/groovy/example/LoginAuthenticationSucessHandler.groovy @@ -0,0 +1,21 @@ +package example + +import grails.events.EventPublisher +import grails.plugin.springsecurity.rest.RestAuthenticationSuccessHandler +import org.springframework.security.core.Authentication + +import javax.servlet.ServletException +import javax.servlet.http.HttpServletRequest +import javax.servlet.http.HttpServletResponse + +class LoginAuthenticationSucessHandler extends RestAuthenticationSuccessHandler implements EventPublisher { + + TestService testService + + @Override + void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException { + super.onAuthenticationSuccess(request, response, authentication) + testService.testDataService(1l) + } + +} diff --git a/settings.gradle b/settings.gradle index 7e914609da..19c2dbb07b 100644 --- a/settings.gradle +++ b/settings.gradle @@ -29,5 +29,9 @@ project(":examples-standalone-hibernate5").projectDir = new File(settingsDir, "e include "examples-spring-boot-hibernate5" project(":examples-spring-boot-hibernate5").projectDir = new File(settingsDir, "examples/spring-boot-hibernate5") +include "examples-test-data-service" +project(":examples-test-data-service").projectDir = new File(settingsDir, "examples/test-data-service") + + findProject(':boot-plugin').name = 'gorm-hibernate5-spring-boot' From fe1c3b49f2078c2ef1048dbb115c286c48a7fa2c Mon Sep 17 00:00:00 2001 From: Puneet Behl Date: Tue, 26 May 2020 16:36:36 +0530 Subject: [PATCH 02/11] #202 Update HibernateDatastoreSpringInitializer to create bean DSL for data services. --- ...HibernateDatastoreSpringInitializer.groovy | 35 ++++++++++++++++--- 1 file changed, 31 insertions(+), 4 deletions(-) diff --git a/grails-plugin/src/main/groovy/grails/orm/bootstrap/HibernateDatastoreSpringInitializer.groovy b/grails-plugin/src/main/groovy/grails/orm/bootstrap/HibernateDatastoreSpringInitializer.groovy index 73d1a12e87..83d0b9bbda 100644 --- a/grails-plugin/src/main/groovy/grails/orm/bootstrap/HibernateDatastoreSpringInitializer.groovy +++ b/grails-plugin/src/main/groovy/grails/orm/bootstrap/HibernateDatastoreSpringInitializer.groovy @@ -16,22 +16,20 @@ package grails.orm.bootstrap import groovy.transform.CompileStatic import groovy.util.logging.Slf4j +import org.codehaus.groovy.transform.trait.Traits import org.grails.datastore.gorm.bootstrap.AbstractDatastoreInitializer import org.grails.datastore.gorm.bootstrap.support.ServiceRegistryFactoryBean import org.grails.datastore.gorm.jdbc.connections.CachedDataSourceConnectionSourceFactory import org.grails.datastore.gorm.support.AbstractDatastorePersistenceContextInterceptor import org.grails.datastore.mapping.core.connections.AbstractConnectionSources import org.grails.datastore.mapping.core.connections.ConnectionSource -import org.grails.datastore.mapping.core.grailsversion.GrailsVersion import org.grails.datastore.mapping.reflect.ClassUtils -import org.grails.datastore.mapping.validation.BeanFactoryValidatorRegistry +import org.grails.datastore.mapping.services.Service import org.grails.orm.hibernate.HibernateDatastore import org.grails.orm.hibernate.cfg.Settings import org.grails.orm.hibernate.connections.HibernateConnectionSourceFactory import org.grails.orm.hibernate.proxy.HibernateProxyHandler import org.grails.orm.hibernate.support.HibernateDatastoreConnectionSourcesRegistrar -import org.grails.spring.beans.factory.InstanceFactoryBean -import org.springframework.beans.factory.BeanFactory import org.springframework.beans.factory.config.MethodInvokingFactoryBean import org.springframework.beans.factory.support.BeanDefinitionRegistry import org.springframework.context.ApplicationContext @@ -42,6 +40,8 @@ import org.springframework.core.env.PropertyResolver import org.springframework.transaction.PlatformTransactionManager import javax.sql.DataSource +import java.beans.Introspector +import java.lang.reflect.Modifier /** * Class that handles the details of initializing GORM for Hibernate @@ -166,6 +166,33 @@ class HibernateDatastoreSpringInitializer extends AbstractDatastoreInitializer { // domain model mapping context, used for configuration grailsDomainClassMappingContext(hibernateDatastore:"getMappingContext") + final Iterator serviceIterator = ServiceLoader.load(Service).iterator() + while(serviceIterator.hasNext()) { + final Service service = serviceIterator.next() + if( service.getClass().simpleName.startsWith('$') ) { + final Class superclass = service.getClass().superclass + if (superclass != null && superclass != Object.class && Modifier.isAbstract(superclass.modifiers)) { + final String decapitalizedServiceName = Introspector.decapitalize(superclass.simpleName) + "$decapitalizedServiceName"(MethodInvokingFactoryBean) { + targetObject = ref('hibernateDatastore') + targetMethod = 'getService' + arguments = [superclass] + } + } + Class[] allInterfaces = org.springframework.util.ClassUtils.getAllInterfaces(service) + for(Class i in allInterfaces) { + if(i != Service && i != GroovyObject && !i.name.endsWith(Traits.FIELD_HELPER) ) { + final String decapitalizedServiceName = Introspector.decapitalize(i.simpleName) + "$decapitalizedServiceName"(MethodInvokingFactoryBean) { + targetObject = ref('hibernateDatastore') + targetMethod = 'getService' + arguments = [i] + } + } + } + } + } + if(isGrailsPresent) { if(ClassUtils.isPresent("org.grails.plugin.hibernate.support.AggregatePersistenceContextInterceptor")) { ClassLoader cl = ClassUtils.getClassLoader() From c4eccc86197b93535df6ef34465317d7b11d4110 Mon Sep 17 00:00:00 2001 From: Puneet Behl Date: Fri, 29 May 2020 00:46:54 +0530 Subject: [PATCH 03/11] #202 Update test to check Autowiring of the Data Service by type --- examples/test-data-service/build.gradle | 3 --- .../grails-app/conf/logback.groovy | 2 ++ .../grails-app/conf/spring/resources.groovy | 3 +++ .../grails-app/domain/example/Person.groovy | 7 +++++++ .../services/example/LibraryService.groovy | 8 ++++++++ .../services/example/PersonService.groovy | 10 ++++++++++ .../services/example/TestService.groovy | 4 ++++ .../groovy/example/TestServiceSpec.groovy | 16 ++++++++++++++++ .../src/main/groovy/example/TestBean.groovy | 15 +++++++++++++++ 9 files changed, 65 insertions(+), 3 deletions(-) create mode 100644 examples/test-data-service/grails-app/domain/example/Person.groovy create mode 100644 examples/test-data-service/grails-app/services/example/PersonService.groovy create mode 100644 examples/test-data-service/src/main/groovy/example/TestBean.groovy diff --git a/examples/test-data-service/build.gradle b/examples/test-data-service/build.gradle index 7e60cce9e9..72e86a6677 100644 --- a/examples/test-data-service/build.gradle +++ b/examples/test-data-service/build.gradle @@ -32,13 +32,10 @@ dependencies { compile "org.grails.plugins:views-json" compile "org.grails.plugins:views-json-templates" compile 'org.grails.plugins:spring-security-rest:3.0.1' - compileOnly "io.micronaut:micronaut-inject-groovy" - console "org.grails:grails-console" profile "org.grails.profiles:rest-api" runtime "org.glassfish.web:el-impl:2.1.2-b03" runtime "org.apache.tomcat:tomcat-jdbc" runtime "javax.xml.bind:jaxb-api:2.3.0" testCompile "org.grails:grails-gorm-testing-support" - testCompile "io.micronaut:micronaut-http-client" testCompile "org.grails:grails-web-testing-support" } diff --git a/examples/test-data-service/grails-app/conf/logback.groovy b/examples/test-data-service/grails-app/conf/logback.groovy index b835215c1e..640e30ec71 100644 --- a/examples/test-data-service/grails-app/conf/logback.groovy +++ b/examples/test-data-service/grails-app/conf/logback.groovy @@ -35,3 +35,5 @@ if (Environment.isDevelopmentMode() && targetDir != null) { logger("StackTrace", ERROR, ['FULL_STACKTRACE'], false) } root(ERROR, ['STDOUT']) + +logger("org.springframework.core", DEBUG, ['STDOUT'], false) diff --git a/examples/test-data-service/grails-app/conf/spring/resources.groovy b/examples/test-data-service/grails-app/conf/spring/resources.groovy index 2528520272..fe2abe800e 100644 --- a/examples/test-data-service/grails-app/conf/spring/resources.groovy +++ b/examples/test-data-service/grails-app/conf/spring/resources.groovy @@ -1,4 +1,5 @@ import example.LoginAuthenticationSucessHandler +import example.TestBean // Place your Spring DSL code here beans = { @@ -6,4 +7,6 @@ beans = { restAuthenticationSuccessHandler(LoginAuthenticationSucessHandler) { testService = ref('testService') } + + testBean(TestBean) } diff --git a/examples/test-data-service/grails-app/domain/example/Person.groovy b/examples/test-data-service/grails-app/domain/example/Person.groovy new file mode 100644 index 0000000000..864ae87784 --- /dev/null +++ b/examples/test-data-service/grails-app/domain/example/Person.groovy @@ -0,0 +1,7 @@ +package example + +class Person { + + String firstName + String lastName +} diff --git a/examples/test-data-service/grails-app/services/example/LibraryService.groovy b/examples/test-data-service/grails-app/services/example/LibraryService.groovy index 1e6c0eb3ea..3ed9eadd88 100644 --- a/examples/test-data-service/grails-app/services/example/LibraryService.groovy +++ b/examples/test-data-service/grails-app/services/example/LibraryService.groovy @@ -6,9 +6,17 @@ import grails.gorm.transactions.Transactional class LibraryService { BookService bookService + PersonService personService + @Transactional(readOnly = true) Boolean bookExists(Serializable id) { assert bookService != null bookService.get(id) } + + Person addMember(String firstName, String lastName) { + assert personService != null + personService.save(firstName, lastName) + } + } diff --git a/examples/test-data-service/grails-app/services/example/PersonService.groovy b/examples/test-data-service/grails-app/services/example/PersonService.groovy new file mode 100644 index 0000000000..643d427a07 --- /dev/null +++ b/examples/test-data-service/grails-app/services/example/PersonService.groovy @@ -0,0 +1,10 @@ +package example + +import grails.gorm.services.Service + +@Service(Person) +abstract class PersonService { + + abstract Person save(String firstName, String lastName) + +} diff --git a/examples/test-data-service/grails-app/services/example/TestService.groovy b/examples/test-data-service/grails-app/services/example/TestService.groovy index 99e7a54963..233fa65342 100644 --- a/examples/test-data-service/grails-app/services/example/TestService.groovy +++ b/examples/test-data-service/grails-app/services/example/TestService.groovy @@ -7,4 +7,8 @@ class TestService { Boolean testDataService(Serializable id) { libraryService.bookExists(id) } + + Person save(String firstName, String lastName) { + libraryService.addMember(firstName, lastName) + } } diff --git a/examples/test-data-service/src/integration-test/groovy/example/TestServiceSpec.groovy b/examples/test-data-service/src/integration-test/groovy/example/TestServiceSpec.groovy index eb506879a0..0f4978249b 100644 --- a/examples/test-data-service/src/integration-test/groovy/example/TestServiceSpec.groovy +++ b/examples/test-data-service/src/integration-test/groovy/example/TestServiceSpec.groovy @@ -2,6 +2,7 @@ package example import grails.gorm.transactions.Rollback import grails.testing.mixin.integration.Integration +import org.springframework.beans.factory.annotation.Autowired import spock.lang.Specification @Integration @@ -9,6 +10,10 @@ import spock.lang.Specification class TestServiceSpec extends Specification { TestService testService + TestBean testBean + + @Autowired + List bookServiceList void "test data-service is loaded correctly"() { when: @@ -17,4 +22,15 @@ class TestServiceSpec extends Specification { then: noExceptionThrown() } + + void "test autowire by type"() { + + expect: + testBean.bookRepo != null + } + + void "test that there is only one bookService"() { + expect: + bookServiceList.size() == 1 + } } diff --git a/examples/test-data-service/src/main/groovy/example/TestBean.groovy b/examples/test-data-service/src/main/groovy/example/TestBean.groovy new file mode 100644 index 0000000000..b68921d5ea --- /dev/null +++ b/examples/test-data-service/src/main/groovy/example/TestBean.groovy @@ -0,0 +1,15 @@ +package example + +import org.springframework.beans.factory.annotation.Autowired + +class TestBean { + + @Autowired + BookService bookRepo + + void doSomething() { + assert bookRepo != null + bookRepo.get(1l) + } + +} From c7a84e5b578f1f8a33c44c87712d1f3dd138b34f Mon Sep 17 00:00:00 2001 From: Puneet Behl Date: Fri, 29 May 2020 00:51:41 +0530 Subject: [PATCH 04/11] #202 Improvements to HibernateDatastoreSpringInitializer * Removed hibernateDatastoreServiceRegistry bean as that was redundant. * Use SoftServiceLoader to prevent instantiating the service. --- ...HibernateDatastoreSpringInitializer.groovy | 39 ++++++++++--------- 1 file changed, 20 insertions(+), 19 deletions(-) diff --git a/grails-plugin/src/main/groovy/grails/orm/bootstrap/HibernateDatastoreSpringInitializer.groovy b/grails-plugin/src/main/groovy/grails/orm/bootstrap/HibernateDatastoreSpringInitializer.groovy index 83d0b9bbda..e544a0ba4b 100644 --- a/grails-plugin/src/main/groovy/grails/orm/bootstrap/HibernateDatastoreSpringInitializer.groovy +++ b/grails-plugin/src/main/groovy/grails/orm/bootstrap/HibernateDatastoreSpringInitializer.groovy @@ -21,15 +21,19 @@ import org.grails.datastore.gorm.bootstrap.AbstractDatastoreInitializer import org.grails.datastore.gorm.bootstrap.support.ServiceRegistryFactoryBean import org.grails.datastore.gorm.jdbc.connections.CachedDataSourceConnectionSourceFactory import org.grails.datastore.gorm.support.AbstractDatastorePersistenceContextInterceptor +import org.grails.datastore.mapping.config.GormMethodInvokingFactoryBean import org.grails.datastore.mapping.core.connections.AbstractConnectionSources import org.grails.datastore.mapping.core.connections.ConnectionSource import org.grails.datastore.mapping.reflect.ClassUtils import org.grails.datastore.mapping.services.Service +import org.grails.datastore.mapping.services.ServiceDefinition +import org.grails.datastore.mapping.services.SoftServiceLoader import org.grails.orm.hibernate.HibernateDatastore import org.grails.orm.hibernate.cfg.Settings import org.grails.orm.hibernate.connections.HibernateConnectionSourceFactory import org.grails.orm.hibernate.proxy.HibernateProxyHandler import org.grails.orm.hibernate.support.HibernateDatastoreConnectionSourcesRegistrar +import org.springframework.beans.factory.config.MethodInvokingBean import org.springframework.beans.factory.config.MethodInvokingFactoryBean import org.springframework.beans.factory.support.BeanDefinitionRegistry import org.springframework.context.ApplicationContext @@ -160,33 +164,30 @@ class HibernateDatastoreSpringInitializer extends AbstractDatastoreInitializer { sessionFactory(hibernateDatastore:'getSessionFactory') transactionManager(hibernateDatastore:"getTransactionManager") autoTimestampEventListener(hibernateDatastore:"getAutoTimestampEventListener") - "hibernateDatastoreServiceRegistry"(ServiceRegistryFactoryBean, ref("hibernateDatastore")) getBeanDefinition("transactionManager").beanClass = PlatformTransactionManager hibernateDatastoreConnectionSourcesRegistrar(HibernateDatastoreConnectionSourcesRegistrar, dataSources) // domain model mapping context, used for configuration grailsDomainClassMappingContext(hibernateDatastore:"getMappingContext") - final Iterator serviceIterator = ServiceLoader.load(Service).iterator() - while(serviceIterator.hasNext()) { - final Service service = serviceIterator.next() - if( service.getClass().simpleName.startsWith('$') ) { - final Class superclass = service.getClass().superclass - if (superclass != null && superclass != Object.class && Modifier.isAbstract(superclass.modifiers)) { - final String decapitalizedServiceName = Introspector.decapitalize(superclass.simpleName) - "$decapitalizedServiceName"(MethodInvokingFactoryBean) { - targetObject = ref('hibernateDatastore') - targetMethod = 'getService' - arguments = [superclass] + final SoftServiceLoader services = SoftServiceLoader.load(Service) + for (ServiceDefinition serviceDefinition: services) { + if (serviceDefinition.isPresent()) { + final Class clazz = serviceDefinition.getType() + if (clazz.simpleName.startsWith('$')) { + String serviceClassName = clazz.name - '$' - 'Implementation' + final ClassLoader cl = ClassUtils.classLoader + final Class serviceClass = cl.loadClass(serviceClassName) + + final grails.gorm.services.Service ann = clazz.getAnnotation(grails.gorm.services.Service) + String serviceName = ann?.name() + if(serviceName == null) { + serviceName = Introspector.decapitalize(serviceClass.simpleName) } - } - Class[] allInterfaces = org.springframework.util.ClassUtils.getAllInterfaces(service) - for(Class i in allInterfaces) { - if(i != Service && i != GroovyObject && !i.name.endsWith(Traits.FIELD_HELPER) ) { - final String decapitalizedServiceName = Introspector.decapitalize(i.simpleName) - "$decapitalizedServiceName"(MethodInvokingFactoryBean) { + if (serviceClass != null && serviceClass != Object.class) { + "$serviceName"(GormMethodInvokingFactoryBean) { targetObject = ref('hibernateDatastore') targetMethod = 'getService' - arguments = [i] + arguments = [serviceClass] } } } From eebcc9b46a2ff8c5949b99b913a7ab952536cffb Mon Sep 17 00:00:00 2001 From: Puneet Behl Date: Fri, 29 May 2020 00:55:02 +0530 Subject: [PATCH 05/11] #202 Updated test project class with CompileStatic --- .../main/groovy/example/LoginAuthenticationSucessHandler.groovy | 2 ++ 1 file changed, 2 insertions(+) diff --git a/examples/test-data-service/src/main/groovy/example/LoginAuthenticationSucessHandler.groovy b/examples/test-data-service/src/main/groovy/example/LoginAuthenticationSucessHandler.groovy index 266dfee512..de04002a58 100644 --- a/examples/test-data-service/src/main/groovy/example/LoginAuthenticationSucessHandler.groovy +++ b/examples/test-data-service/src/main/groovy/example/LoginAuthenticationSucessHandler.groovy @@ -2,12 +2,14 @@ package example import grails.events.EventPublisher import grails.plugin.springsecurity.rest.RestAuthenticationSuccessHandler +import groovy.transform.CompileStatic import org.springframework.security.core.Authentication import javax.servlet.ServletException import javax.servlet.http.HttpServletRequest import javax.servlet.http.HttpServletResponse +@CompileStatic class LoginAuthenticationSucessHandler extends RestAuthenticationSuccessHandler implements EventPublisher { TestService testService From 62d79b1e707f56ad652dc8dc484ace439a074b98 Mon Sep 17 00:00:00 2001 From: Puneet Behl Date: Fri, 29 May 2020 01:50:16 +0530 Subject: [PATCH 06/11] #202 Update example-test-data-service logger configuration to remove debug logs. --- examples/test-data-service/grails-app/conf/logback.groovy | 2 -- 1 file changed, 2 deletions(-) diff --git a/examples/test-data-service/grails-app/conf/logback.groovy b/examples/test-data-service/grails-app/conf/logback.groovy index 640e30ec71..b835215c1e 100644 --- a/examples/test-data-service/grails-app/conf/logback.groovy +++ b/examples/test-data-service/grails-app/conf/logback.groovy @@ -35,5 +35,3 @@ if (Environment.isDevelopmentMode() && targetDir != null) { logger("StackTrace", ERROR, ['FULL_STACKTRACE'], false) } root(ERROR, ['STDOUT']) - -logger("org.springframework.core", DEBUG, ['STDOUT'], false) From 7c3bd969811f56888ec91ada03c210882bdb87b5 Mon Sep 17 00:00:00 2001 From: Puneet Behl Date: Fri, 29 May 2020 13:24:00 +0530 Subject: [PATCH 07/11] #202 Improvements to HibernateDatastoreSpringInitializer * Update the `if()` check to filter out some unrelated services. * Rename GormMethodInvokingFactoryBean -> DatastoreServiceMethodInvokingFactoryBean --- .../HibernateDatastoreSpringInitializer.groovy | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/grails-plugin/src/main/groovy/grails/orm/bootstrap/HibernateDatastoreSpringInitializer.groovy b/grails-plugin/src/main/groovy/grails/orm/bootstrap/HibernateDatastoreSpringInitializer.groovy index e544a0ba4b..c8eb4b1db8 100644 --- a/grails-plugin/src/main/groovy/grails/orm/bootstrap/HibernateDatastoreSpringInitializer.groovy +++ b/grails-plugin/src/main/groovy/grails/orm/bootstrap/HibernateDatastoreSpringInitializer.groovy @@ -16,12 +16,10 @@ package grails.orm.bootstrap import groovy.transform.CompileStatic import groovy.util.logging.Slf4j -import org.codehaus.groovy.transform.trait.Traits import org.grails.datastore.gorm.bootstrap.AbstractDatastoreInitializer -import org.grails.datastore.gorm.bootstrap.support.ServiceRegistryFactoryBean import org.grails.datastore.gorm.jdbc.connections.CachedDataSourceConnectionSourceFactory import org.grails.datastore.gorm.support.AbstractDatastorePersistenceContextInterceptor -import org.grails.datastore.mapping.config.GormMethodInvokingFactoryBean +import org.grails.datastore.mapping.config.DatastoreServiceMethodInvokingFactoryBean import org.grails.datastore.mapping.core.connections.AbstractConnectionSources import org.grails.datastore.mapping.core.connections.ConnectionSource import org.grails.datastore.mapping.reflect.ClassUtils @@ -33,8 +31,6 @@ import org.grails.orm.hibernate.cfg.Settings import org.grails.orm.hibernate.connections.HibernateConnectionSourceFactory import org.grails.orm.hibernate.proxy.HibernateProxyHandler import org.grails.orm.hibernate.support.HibernateDatastoreConnectionSourcesRegistrar -import org.springframework.beans.factory.config.MethodInvokingBean -import org.springframework.beans.factory.config.MethodInvokingFactoryBean import org.springframework.beans.factory.support.BeanDefinitionRegistry import org.springframework.context.ApplicationContext import org.springframework.context.ApplicationEventPublisher @@ -45,7 +41,6 @@ import org.springframework.transaction.PlatformTransactionManager import javax.sql.DataSource import java.beans.Introspector -import java.lang.reflect.Modifier /** * Class that handles the details of initializing GORM for Hibernate @@ -173,7 +168,7 @@ class HibernateDatastoreSpringInitializer extends AbstractDatastoreInitializer { for (ServiceDefinition serviceDefinition: services) { if (serviceDefinition.isPresent()) { final Class clazz = serviceDefinition.getType() - if (clazz.simpleName.startsWith('$')) { + if (clazz.simpleName.startsWith('$') && clazz.simpleName.endsWith('Implementation')) { String serviceClassName = clazz.name - '$' - 'Implementation' final ClassLoader cl = ClassUtils.classLoader final Class serviceClass = cl.loadClass(serviceClassName) @@ -184,7 +179,7 @@ class HibernateDatastoreSpringInitializer extends AbstractDatastoreInitializer { serviceName = Introspector.decapitalize(serviceClass.simpleName) } if (serviceClass != null && serviceClass != Object.class) { - "$serviceName"(GormMethodInvokingFactoryBean) { + "$serviceName"(DatastoreServiceMethodInvokingFactoryBean) { targetObject = ref('hibernateDatastore') targetMethod = 'getService' arguments = [serviceClass] From 994a331ec2a3a08b0a903c274547017573af8539 Mon Sep 17 00:00:00 2001 From: Puneet Behl Date: Fri, 29 May 2020 20:56:27 +0530 Subject: [PATCH 08/11] #202 Updated example test-data-service to verify that the autowire by name works for the data service. --- .../integration-test/groovy/example/TestServiceSpec.groovy | 6 ++++++ .../src/main/groovy/example/TestBean.groovy | 5 +++++ 2 files changed, 11 insertions(+) diff --git a/examples/test-data-service/src/integration-test/groovy/example/TestServiceSpec.groovy b/examples/test-data-service/src/integration-test/groovy/example/TestServiceSpec.groovy index 0f4978249b..51a517cb7b 100644 --- a/examples/test-data-service/src/integration-test/groovy/example/TestServiceSpec.groovy +++ b/examples/test-data-service/src/integration-test/groovy/example/TestServiceSpec.groovy @@ -29,6 +29,12 @@ class TestServiceSpec extends Specification { testBean.bookRepo != null } + void "test autowire by name works"() { + + expect: + testBean.bookService != null + } + void "test that there is only one bookService"() { expect: bookServiceList.size() == 1 diff --git a/examples/test-data-service/src/main/groovy/example/TestBean.groovy b/examples/test-data-service/src/main/groovy/example/TestBean.groovy index b68921d5ea..c0e87512aa 100644 --- a/examples/test-data-service/src/main/groovy/example/TestBean.groovy +++ b/examples/test-data-service/src/main/groovy/example/TestBean.groovy @@ -1,12 +1,17 @@ package example import org.springframework.beans.factory.annotation.Autowired +import org.springframework.beans.factory.annotation.Qualifier class TestBean { @Autowired BookService bookRepo + @Autowired + @Qualifier("bookService") + BookService bookService + void doSomething() { assert bookRepo != null bookRepo.get(1l) From 5362b197c7c3f4ada4da7143686aa7bda8c2e966 Mon Sep 17 00:00:00 2001 From: Puneet Behl Date: Tue, 2 Jun 2020 14:30:04 +0530 Subject: [PATCH 09/11] #202 Update HibernateDatastoreSpringInitializer * Use loadServices method from the base class. --- ...HibernateDatastoreSpringInitializer.groovy | 32 ++++--------------- 1 file changed, 6 insertions(+), 26 deletions(-) diff --git a/grails-plugin/src/main/groovy/grails/orm/bootstrap/HibernateDatastoreSpringInitializer.groovy b/grails-plugin/src/main/groovy/grails/orm/bootstrap/HibernateDatastoreSpringInitializer.groovy index c8eb4b1db8..254324eca8 100644 --- a/grails-plugin/src/main/groovy/grails/orm/bootstrap/HibernateDatastoreSpringInitializer.groovy +++ b/grails-plugin/src/main/groovy/grails/orm/bootstrap/HibernateDatastoreSpringInitializer.groovy @@ -23,9 +23,6 @@ import org.grails.datastore.mapping.config.DatastoreServiceMethodInvokingFactory import org.grails.datastore.mapping.core.connections.AbstractConnectionSources import org.grails.datastore.mapping.core.connections.ConnectionSource import org.grails.datastore.mapping.reflect.ClassUtils -import org.grails.datastore.mapping.services.Service -import org.grails.datastore.mapping.services.ServiceDefinition -import org.grails.datastore.mapping.services.SoftServiceLoader import org.grails.orm.hibernate.HibernateDatastore import org.grails.orm.hibernate.cfg.Settings import org.grails.orm.hibernate.connections.HibernateConnectionSourceFactory @@ -40,7 +37,6 @@ import org.springframework.core.env.PropertyResolver import org.springframework.transaction.PlatformTransactionManager import javax.sql.DataSource -import java.beans.Introspector /** * Class that handles the details of initializing GORM for Hibernate @@ -164,30 +160,14 @@ class HibernateDatastoreSpringInitializer extends AbstractDatastoreInitializer { // domain model mapping context, used for configuration grailsDomainClassMappingContext(hibernateDatastore:"getMappingContext") - final SoftServiceLoader services = SoftServiceLoader.load(Service) - for (ServiceDefinition serviceDefinition: services) { - if (serviceDefinition.isPresent()) { - final Class clazz = serviceDefinition.getType() - if (clazz.simpleName.startsWith('$') && clazz.simpleName.endsWith('Implementation')) { - String serviceClassName = clazz.name - '$' - 'Implementation' - final ClassLoader cl = ClassUtils.classLoader - final Class serviceClass = cl.loadClass(serviceClassName) - - final grails.gorm.services.Service ann = clazz.getAnnotation(grails.gorm.services.Service) - String serviceName = ann?.name() - if(serviceName == null) { - serviceName = Introspector.decapitalize(serviceClass.simpleName) - } - if (serviceClass != null && serviceClass != Object.class) { - "$serviceName"(DatastoreServiceMethodInvokingFactoryBean) { - targetObject = ref('hibernateDatastore') - targetMethod = 'getService' - arguments = [serviceClass] - } + loadDataServices(null) + .each {serviceName, serviceClass-> + "$serviceName"(DatastoreServiceMethodInvokingFactoryBean) { + targetObject = ref("hibernateDatastore") + targetMethod = 'getService' + arguments = [serviceClass] } } - } - } if(isGrailsPresent) { if(ClassUtils.isPresent("org.grails.plugin.hibernate.support.AggregatePersistenceContextInterceptor")) { From 62089654038b4e0b13781734787dfaeb6b17373c Mon Sep 17 00:00:00 2001 From: Puneet Behl Date: Tue, 2 Jun 2020 14:31:25 +0530 Subject: [PATCH 10/11] #202 Update tests Use `def` to verify autowire by name. --- .../test-data-service/src/main/groovy/example/TestBean.groovy | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/test-data-service/src/main/groovy/example/TestBean.groovy b/examples/test-data-service/src/main/groovy/example/TestBean.groovy index c0e87512aa..1892732243 100644 --- a/examples/test-data-service/src/main/groovy/example/TestBean.groovy +++ b/examples/test-data-service/src/main/groovy/example/TestBean.groovy @@ -10,7 +10,7 @@ class TestBean { @Autowired @Qualifier("bookService") - BookService bookService + def bookService void doSomething() { assert bookRepo != null From e990be85088bc0e8b65798525861e47be5155aea Mon Sep 17 00:00:00 2001 From: Puneet Behl Date: Tue, 2 Jun 2020 14:32:10 +0530 Subject: [PATCH 11/11] #202 Added tests * to verify that regular Grails service correctly autowire by type in the Data service. --- .../grails-app/domain/example/Student.groovy | 7 +++++++ .../services/example/StudentService.groovy | 19 +++++++++++++++++++ .../groovy/example/StudentServiceSpec.groovy | 19 +++++++++++++++++++ 3 files changed, 45 insertions(+) create mode 100644 examples/test-data-service/grails-app/domain/example/Student.groovy create mode 100644 examples/test-data-service/grails-app/services/example/StudentService.groovy create mode 100644 examples/test-data-service/src/integration-test/groovy/example/StudentServiceSpec.groovy diff --git a/examples/test-data-service/grails-app/domain/example/Student.groovy b/examples/test-data-service/grails-app/domain/example/Student.groovy new file mode 100644 index 0000000000..b1fb751f78 --- /dev/null +++ b/examples/test-data-service/grails-app/domain/example/Student.groovy @@ -0,0 +1,7 @@ +package example + +class Student { + + String firstName + String lastName +} diff --git a/examples/test-data-service/grails-app/services/example/StudentService.groovy b/examples/test-data-service/grails-app/services/example/StudentService.groovy new file mode 100644 index 0000000000..1c3abcef71 --- /dev/null +++ b/examples/test-data-service/grails-app/services/example/StudentService.groovy @@ -0,0 +1,19 @@ +package example + +import grails.gorm.services.Service +import grails.gorm.transactions.Transactional +import org.springframework.beans.factory.annotation.Autowired + +@Service(Student) +abstract class StudentService { + + @Autowired + TestService testServiceBean + + abstract Student get(Serializable id) + + @Transactional + List booksAllocated(Serializable studentId) { + assert testServiceBean != null + } +} diff --git a/examples/test-data-service/src/integration-test/groovy/example/StudentServiceSpec.groovy b/examples/test-data-service/src/integration-test/groovy/example/StudentServiceSpec.groovy new file mode 100644 index 0000000000..8480e5d0e4 --- /dev/null +++ b/examples/test-data-service/src/integration-test/groovy/example/StudentServiceSpec.groovy @@ -0,0 +1,19 @@ +package example + +import grails.gorm.transactions.Rollback +import grails.testing.mixin.integration.Integration +import spock.lang.Specification + +@Integration +@Rollback +class StudentServiceSpec extends Specification { + + StudentService studentService + + void "test regular service autowire by type in a Data Service"() { + expect: + studentService.testServiceBean != null + studentService.testServiceBean.libraryService != null + + } +}