I am working on a split Grails-Project, see here: grails3 using a plugin for domain classes, specifically spring security User/Role
Basically I am trying to put my Domain Classes into a plugin that can be used in multiple other projects.
I am getting this Exception when trying to start my Server:
ERROR org.springframework.boot.SpringApplication - Application startup failed
java.lang.ArrayIndexOutOfBoundsException: 0
at wcommon.WebsiteRole.<init>(WebsiteRole.groovy:15)
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:57)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:526)
at org.springsource.loaded.ri.ReflectiveInterceptor.jlrConstructorNewInstance(ReflectiveInterceptor.java:1075)
at org.codehaus.groovy.reflection.CachedConstructor.invoke(CachedConstructor.java:83)
at org.codehaus.groovy.runtime.callsite.ConstructorSite$ConstructorSiteNoUnwrapNoCoerce.callConstructor(ConstructorSite.java:105)
at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCallConstructor(CallSiteArray.java:60)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:125)
at BootStrap$_closure1.doCall(BootStrap.groovy:9)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at org.springsource.loaded.ri.ReflectiveInterceptor.jlrMethodInvoke(ReflectiveInterceptor.java:1426)
at org.codehaus.groovy.ron.CachedMethod.invoke(CachedMethod.java:93)
at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:325)
at org.codehaus.groovy.runtime.metaclass.ClosureMetaClass.invokeMethod(ClosureMetaClass.java:294)
at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1021)
at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1086)
at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1021)
at groovy.lang.Closure.call(Closure.java:426)
at groovy.lang.Closure.call(Closure.java:420)
at grails.util.Environment.evaluateEnvironmentSpecificBlock(Environment.java:437)
at grails.util.Environment.executeForEnvironment(Environment.java:430)
at grails.util.Environment.executeForCurrentEnvironment(Environment.java:406)
at org.grails.web.servlet.boostrap.DefaultGrailsBootstrapClass.callInit(DefaultGrailsBootstrapClass.java:62)
at org.grails.web.servlet.context.GrailsConfigUtils.executeGrailsBootstraps(GrailsConfigUtils.java:65)
at org.grails.plugins.web.servlet.context.BootStrapClassRunner.onStartup(BootStrapClassRunner.groovy:53)
at grails.boot.config.GrailsApplicationPostProcessor.onApplicationEvent(GrailsApplicationPostProcessor.groovy:240)
at grails.boot.config.GrailsApplicationPostProcessor.onApplicationEvent(GrailsApplicationPostProcessor.groovy)
at org.springframework.context.event.SimpleApplicationEventMulticaster.invokeListener(SimpleApplicationEventMulticaster.java:163)
at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:136)
at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:381)
at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:335)
at org.springframework.context.support.AbstractApplicationContext.finishRefresh(AbstractApplicationContext.java:855)
at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.finishRefresh(EmbeddedWebApplicationContext.java:140)
at org.spmework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:541)
at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.refresh(EmbeddedWebApplicationContext.java:118)
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:766)
at org.springframework.boot.SpringApplication.createAndRefreshContext(SpringApplication.java:361)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:307)
at grails.boot.GrailsApp.run(GrailsApp.groovy:55)
at grails.boot.GrailsApp.run(GrailsApp.groovy:365)
at grails.boot.GrailsApp.run(GrailsApp.groovy:354)
at grails.boot.GrailsApp$run.call(Unknown Source)
at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:48)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:113)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:133)
at webp.Application.main(Application.groovy:8)
:WebP:bootRun FAILED
I have no idea at all why this happens. The line in question is a call to this() Why would that throw such an exception? My initial reaction was to remove this() and add an empty default constructor to the class, but that apparently broke the Dependency Injection, which caused the issue described in the question I liked above.
Code involved from my side is:
package wcommon
import groovy.transform.EqualsAndHashCode
import groovy.transform.ToString
@EqualsAndHashCode(includes='authority')
@ToString(includes='authority', includeNames=true, includePackage=false)
class WebsiteRole implements Serializable {
private static final long serialVersionUID = 1
String authority
WebsiteRole(String authority) {
**this();** // line 15
this.authority = authority
}
static constraints = {
authority blank: false, unique: true
}
static mapping = {
cache true
}
}
import grails.core.GrailsApplication
import wcommon.WebsiteUserWebsiteRole;
class BootStrap {
GrailsApplication grailsApplication
def init = { servletContext ->
**WebsiteUserWebsiteRole.initDefaults(grailsApplication)** //line 9
}
def destroy = {
}
}
And the initDefaults function looks like this:
**static def initDefaults(GrailsApplication grailsApplication) {
def patientRole = new WebsiteRole("ROLE_PATIENT").save();
def adminRole = new WebsiteRole("ROLE_ADMIN").save()
def doctorRole = new WebsiteRole("ROLE_DOCTOR").save()
def nurseRole = new WebsiteRole("ROLE_NURSE").save()
def serverRole = new WebsiteRole("ROLE_SERVER").save()
def user1 = new WebsiteUser("admin", "password").save()
WebsiteUserWebsiteRole.create user1, adminRole, true
def user2 = new WebsiteUser("doctor", "password").save()
WebsiteUserWebsiteRole.create user2, doctorRole, true
def user3 = new WebsiteUser("nurse", "password").save()
WebsiteUserWebsiteRole.create user3, nurseRole, true
}**
EDIT: Using Grails Version 3.1.1
java -version is 1.7.0_79
spring security plugin is 'org.grails.plugins:spring-security-core:3.0.3'
I am not quite sure which Database version I am using, I am just using the by default included h2, the dependency just says: runtime "com.h2database:h2"
The Project setup in general is that my Domain classes are in one project, which is a plugin project. The Project that has the issues includes the Domain classes via compile project(':WebCommon') in the dependencies. Compile works fine.
EDIT 2: So if I remove the this() and add a default constructor it does not throw the exception, however the dependency injection of the spring security service in this class does not work:
package wcommon
import grails.plugin.springsecurity.SpringSecurityService;
import groovy.transform.EqualsAndHashCode
import groovy.transform.ToString
@EqualsAndHashCode(includes='username')
@ToString(includes='username', includeNames=true, includePackage=false)
class WebsiteUser implements Serializable {
private static final long serialVersionUID = 1
public SpringSecurityService springSecurityService
String username
String password
boolean enabled = true
boolean accountExpired
boolean accountLocked
boolean passwordExpired
WebsiteUser() {
}
WebsiteUser(String username, String password) {
this.username = username
this.password = password
}
Set<WebsiteRole> getAuthorities() {
WebsiteUserWebsiteRole.findAllByWebsiteUser(this)*.websiteRole
}
def beforeInsert() {
encodePassword()
}
def beforeUpdate() {
if (isDirty('password')) {
encodePassword()
}
}
protected void encodePassword() {
println springSecurityService // prints null
password = springSecurityService?.passwordEncoder ? springSecurityService.encodePassword(password) : password
}
static transients = ['springSecurityService']
static constraints = {
username blank: false, unique: true
password blank: false
}
static mapping = {
password column: '`password`'
}
}
After I changed the property from just def springSecurityService to public SpringSecurityService it told me that an indirect dependency to HttpServletRequest. Adding these dependencies to the plugin project fixes that, but this doesn't change anything about the injection not working:
compile "org.springframework.boot:spring-boot-starter-tomcat"
compile "org.grails:grails-web-boot"
I thought that my changes to the User and Role classes to fix the this() issue caused the dependency injection problem. But maybe I am wrong and both of the issues are caused by something else, probably related to my project setup. I dunno, this is all really confusing, been fighting with grails for since yesterday.
EDIT: To get it to work I now first fixed the Exception by removing this() and adding the default constructor and then I injected a springSecurityService into the Bootstrap of my main project that is used to set a static public field on the class in the plugin project that ssneeds the springSecurityService. Ugly, but it works better than anything I've tried so far. ... okay actually now this simple test of a controller:
import grails.converters.JSON
import grails.plugin.springsecurity.annotation.Secured
@Secured(['ROLE_ADMIN', 'ROLE_SERVER'])
class ApiController {
def index() {
render getAuthenticatedUser() as JSON
}
}
throws a MissingMethodException about getAuthenticatedUser()
That Controller was added via create-controller I guess this whole "split the project into multiple parts" isn't working at all and broke something very very deep down that causes all these issues to show up. I think instead of trying to split my project I'll just make a single web-app project that is configured with a flag that tells it which functions to activate and deactivate....
If somebody can tell me how to do a properly split grails project with common domain objects in a common library please see this question and post there: grails3 using a plugin for domain classes, specifically spring security User/Role
wcommon.WebsiteRole
- bold 15 line and code ofBootStrap.groovy
- bold 9 line – Michal_Szulcthis()
in a class that does not have a no-arg constructor? – Jeff Scott Brown