【问题标题】:ArrayIndexOutOfBoundsException: 0 in this() of Grails Domain ClassArrayIndexOutOfBoundsException: 0 in this() of Grails Domain Class
【发布时间】:2016-06-23 21:46:11
【问题描述】:

我正在开发一个拆分的 Grails 项目,请参见此处: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() 的调用 为什么会抛出这样的异常? 我最初的反应是删除 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 安全插件是 'org.grails.plugins:spring-security-core:3.0.3'

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

项目设置通常是我的域类在一个项目中,这是一个插件项目。 有问题的项目包括域类通过 编译项目(':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 更改为 public SpringSecurityService 后,它告诉我间接依赖于 HttpServletRequest。将这些依赖项添加到插件项目可以解决这个问题,但这并不会改变注入不起作用的任何内容:

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

我认为我对 User 和 Role 类的更改以修复 this() 问题导致了依赖注入问题。但也许我错了,这两个问题都是由其他原因引起的,可能与我的项目设置有关。 我不知道,这一切真的很混乱,从昨天开始就一直在和 grails 战斗。

编辑: 为了让它工作,我现在首先通过删除 this() 并添加默认构造函数来修复异常,然后我将 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 应用程序项目,该标志告诉它激活和停用哪些功能....

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

【问题讨论】:

  • 请显示wcommon.WebsiteRole的代码 - 粗体15行和BootStrap.groovy的代码 - 粗体9行
  • 为什么要在没有无参数构造函数的类中调用this()
  • 该代码不是我写的,它是由 grails spring security 插件通过命令 s2-quickstart 生成的。添加 this() 解决了这个问题,但它不应该存在,从我在别处读到的内容来看,应该以某种方式生成无参数构造函数,并且对于依赖注入很重要。添加无参数构造函数会导致我的用户类中的依赖注入失败。在另一个项目中,生成的 Role 和 User 类在未实现时也会调用 this() 并且它在那里工作。
  • 此外,您使用的是哪个版本的 Grails、spring-security、db 和 jdk?
  • “我没有编写该代码,它是由 grails spring 安全插件通过命令 s2-quickstart 生成的。” - 这让我感到惊讶。这是插件中的一个错误。

标签: grails groovy


【解决方案1】:

您可以安全地从这些类(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 }

【讨论】:

  • 删除 this() 修复了一个特定问题,但编辑中描述的其他问题仍然存在。我真的不知道从哪里开始描述出了什么问题。似乎根本没有任何作用。
  • 您能否详细说明“基本上我正在尝试将我的域类放入可用于多个其他项目的插件中”?似乎您应该研究一下 Spring Security CAS。
  • 我将有一些域类,例如“Person”、“Role”、“Group”、“Medication”等……它们应该在两个不同的 grails 项目中作为域类可用。这些包括 User 和 Role 类,但还有更多。基本上我只想把我的领域类放到一个库中。
  • 您可以探索创建 grail 插件并托管在本地存储库中。 grails.github.io/grails-doc/latest/guide/single.html#plugins
  • 该文档的多项目和插件部分是我从昨天开始尝试的起点。我在 stackoverflow 上提出的两个问题总结了我在这方面取得的成功。它只是行不通。发生多个错误,但我从未摆脱所有错误。 grails 3.1.3 似乎没有这样的工作示例
猜你喜欢
  • 2022-12-27
  • 2018-01-11
  • 1970-01-01
  • 2022-12-01
  • 2021-08-17
  • 1970-01-01
  • 2022-12-04
  • 1970-01-01
  • 2020-11-14
相关资源
最近更新 更多