ArrayIndexOutOfBoundsException:在Grails Domain Class

时间:2016-03-09 13:27:40

标签: grails groovy

我正在处理拆分的Grails-Project,请参阅此处:grails3 using a plugin for domain classes, specifically spring security User/Role

基本上我试图将我的域类放入一个可以在其他多个项目中使用的插件中。

尝试启动服务器时出现此异常:

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

我根本不知道为什么会这样。 有问题的行是对此的调用() 为什么会抛出这样的例外? 我最初的反应是删除this()并向类中添加一个空的默认构造函数,但这显然打破了依赖注入,这导致了上面我喜欢的问题中描述的问题。

我方的代码是:

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 = {
    }
}

initDefaults函数如下所示:

**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


}**

修改 使用Grails版本3.1.1

java -version是1.7.0_79

spring security plugin是'org.grails.plugins:spring-security-core:3.0.3'

我不太确定我正在使用哪个数据库版本,我只是使用默认包含的h2,依赖项只是说: 运行时“com.h2database:h2”

项目设置一般是我的Domain类在一个项目中,这是一个插件项目。 具有问题的项目包括Domain classes via 编译项目(':WebCommon') 在依赖项中。编译工作正常。

编辑2: 因此,如果我删除this()并添加一个默认构造函数,它不会抛出异常,但是这个类中的spring安全服务的依赖注入不起作用:

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`'
    }
}

在我将属性从def springSecurityService更改为公共SpringSecurityService之后,它告诉我对HttpServletRequest的间接依赖。将这些依赖项添加到插件项目中可以解决这个问题,但这并没有改变注入不起作用的任何内容:

compile "org.springframework.boot:spring-boot-starter-tomcat"
compile "org.grails:grails-web-boot"

我认为我修改用户和角色类来修复this()问题导致了依赖注入问题。但也许我错了,这两个问题都是由其他东西引起的,可能与我的项目设置有关。 我不知道,这一切都让人感到困惑,从昨天起就开始与Grails斗争。

修改 为了使它工作,我现在首先通过删除this()并添加默认构造函数来修复Exception,然后我将springSecurityService注入到我的主项目的Bootstrap中,该项目用于在插件项目中的类上设置静态公共字段这需要springSecurityService。 丑陋,但它比我迄今为止尝试过的任何东西都要好。 ......好吧,现在这个控制器的简单测试:

import grails.converters.JSON
import grails.plugin.springsecurity.annotation.Secured

@Secured(['ROLE_ADMIN', 'ROLE_SERVER'])
class ApiController {

    def index() {
        render getAuthenticatedUser() as JSON
    }
}

抛出关于getAuthenticatedUser()

的MissingMethodException

该控制器是通过create-controller添加的 我猜这整个“将项目分成多个部分”根本不起作用,并且非常深入地破坏了导致所有这些问题出现的问题。我认为不是试图拆分我的项目,而是只创建一个配置了一个标志的web-app项目,该标志告诉它激活和停用哪些函数....

如果有人可以告诉我如何在公共库中使用常见域对象正确拆分grails项目,请查看此问题并发布到那里: grails3 using a plugin for domain classes, specifically spring security User/Role

1 个答案:

答案 0 :(得分:0)

您可以安全地从这些类(WebsiteUserWebsiteRoleWebsiteUserWebsiteRole类)中删除所有构造函数。这也应该解决bean注入问题。您可以使用所有地图样式构造函数,而不是在init中调用它们。

static def initDefaults(GrailsApplication grailsApplication) { def patientRole = new WebsiteRole(authority: "ROLE_PATIENT").save(); ... def userX = new WebsiteUser(username:"nurse", password:"password").save() WebsiteUserWebsiteRole.create user3, nurseRole, true }