`
hax
  • 浏览: 964974 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

Grails陷阱之一

    博客分类:
  • MISC
阅读更多
最近在摆弄Grails,感觉Grails还是很好用的,不过还是遇到一些小问题。因为是基于groovy这样的动态语言,因此许多问题是要到运行时才抛出异常,而有些时候所抛出的异常并不能反应问题的实质,结果往往令人摸不到头脑,从而构成了陷阱(gotchas)。我也经过了多次这样的抓狂经历。

Grails陷阱之一:Domain Class 中的关联不能指向抽象类

Grails的domain class可以继承抽象类。比如:
abstract class Pet {
	String name
	boolean eat(Food food) {
		println("$name is eating ${food.toString()}...")
	}
}
class Cat extends Pet {
}
class Dog extends Pet {
}

abstract class Food {
}
class Fish extends Food {
	String toString() { 'a fish' }
}
class Bone extends Food {
	String toString() { 'a bone' }
}

class Person {
	
	String name
	
	boolean feed(Pet pet, Food food) {
		pet.eat(food)
	}
}

/**********************************************************/

import grails.test.*

class FeedPetTests extends GrailsUnitTestCase {
    protected void setUp() {
        super.setUp()
    }

    protected void tearDown() {
        super.tearDown()
    }

    void testFeed() {
		def hax = new Person(name:'Hax')
		def tom = new Cat(name:'Tom')
		def snoopy = new Dog(name:'Snoopy')
		def fish = new Fish()
		def bone = new Bone()
		hax.feed(tom, fish)
		hax.feed(tom, bone)
		hax.feed(snoopy, fish)
		hax.feed(snoopy, bone)
    }
}


上述代码可以编译和运行成功。
--Output from testFeed--
Tom is eating a fish...
Tom is eating a bone...
Snoopy is eating a fish...
Snoopy is eating a bone...


如果我们给Person加上一个pets关联的话:

class Person {
	
    static hasMany = [pets:Pet] // 关联到抽象类Pet

	String name
	
	boolean feed(Pet pet, Food food) {
		pet.eat(food)
	}
}


结果可以编译,但是运行时出现异常:

gant.TargetExecutionException: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'messageSource': Initialization of bean failed; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'transactionManager': Cannot resolve reference to bean 'sessionFactory' while setting bean property 'sessionFactory'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'sessionFactory': Invocation of init method failed; nested exception is java.lang.NullPointerException

        at gant.Gant$_dispatch_closure4.doCall(Gant.groovy:331)
        at gant.Gant$_dispatch_closure6.doCall(Gant.groovy:334)
        at gant.Gant$_dispatch_closure6.doCall(Gant.groovy)
        at gant.Gant.withBuildListeners(Gant.groovy:344)
        at gant.Gant.this$2$withBuildListeners(Gant.groovy)
        at gant.Gant$this$2$withBuildListeners.callCurrent(Unknown Source)
        at gant.Gant.dispatch(Gant.groovy:334)
        at gant.Gant.this$2$dispatch(Gant.groovy)
        at gant.Gant.invokeMethod(Gant.groovy)
        at gant.Gant.processTargets(Gant.groovy:495)
        at gant.Gant.processTargets(Gant.groovy:480)
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'messageSource': Initialization of bean failed; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'transactionManager': Cannot resolve reference to bean 'sessionFactory' while setting bean property 'sessionFactory'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'sessionFactory': Invocation of init method failed; nested exception is java.lang.NullPointerException
        at java.security.AccessController.doPrivileged(Native Method)
        at _GrailsBootstrap_groovy$_run_closure2_closure13.doCall(_GrailsBootstrap_groovy:86)
        at _GrailsBootstrap_groovy$_run_closure2_closure13.doCall(_GrailsBootstrap_groovy)
        at _GrailsSettings_groovy$_run_closure10.doCall(_GrailsSettings_groovy:269)
        at _GrailsBootstrap_groovy$_run_closure2.doCall(_GrailsBootstrap_groovy:84)
        at _GrailsBootstrap_groovy$_run_closure7.doCall(_GrailsBootstrap_groovy:142)
        at _GrailsTest_groovy$_run_closure7.doCall(_GrailsTest_groovy:238)
        at _GrailsTest_groovy$_run_closure7.doCall(_GrailsTest_groovy)
        at _GrailsTest_groovy$_run_closure1_closure19.doCall(_GrailsTest_groovy:106)
        at _GrailsTest_groovy$_run_closure1.doCall(_GrailsTest_groovy:92)
        at TestApp$_run_closure1.doCall(TestApp.groovy:66)
        at gant.Gant$_dispatch_closure4.doCall(Gant.groovy:324)
        ... 10 more
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'transactionManager': Cannot resolve reference to bean 'sessionFactory' while setting bean property 'sessionFactory'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'sessionFactory': Invocation of init method failed; nested exception is java.lang.NullPointerException
        at java.security.AccessController.doPrivileged(Native Method)
        ... 22 more
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'sessionFactory': Invocation of init method failed; nested exception is java.lang.NullPointerException

        at java.security.AccessController.doPrivileged(Native Method)
        ... 23 more
Caused by: java.lang.NullPointerException
        ... 24 more


光看这些异常你肯定丈二和尚摸不着头脑。我就在这个上栽了跟头,浪费了好多时间去定位问题根源。

问题本身其实不难理解,涉及到数据库关联的,不管是一对一、一对多或多对多,都要指向一个实际的数据库表,而grails是不会为抽象类建立对应的数据库表的,也就是说,在grails中抽象类本身并不是domain class,而只是提供了一种代码复用的手段(也就是节约了一点重复性代码,减少了一些C&P)。

解决方法很简单,就是把Pet抽象类改为具体类,或者修改你的关联,不要关联到抽象类,而是直接关联到具体类。

类似的,如果你关联了一个interface,也会抛出差不多的异常,不过在/grails-app/domain下放置interface会编译失败,你必须放到/src/groovy下,而所以一般来说你不太会遇到interface的问题。
分享到:
评论

相关推荐

    Grails Grails Grails

    Grails 是一个基于 Groovy 语言的开源Web应用程序框架,它构建在Java平台之上,旨在简化开发过程并提高生产力。Grails 的设计深受Ruby on Rails的影响,提供了MVC(模型-视图-控制器)架构模式,允许开发者快速构建...

    Grails开发之(Rest教程).pdf

    标题中提到的"Grails开发之(Rest教程)"表明本文是一份关于Grails框架下进行RESTful服务开发的教程。Grails是一个使用Groovy语言编写的高生产力的框架,其使用约定优于配置的理念,允许快速开发Web应用程序。...

    Grails开发之(Rest教程).docx

    在Grails中开发RESTful API是一项常见的任务,这个文档提供了基于Grails 3.1.5版本的REST教程。Grails是一种基于Groovy语言的开源Web应用框架,它利用了Spring Boot的功能,使得构建现代互联网应用程序变得更加高效...

    Grails权威指南 Grails权威指南

    《Grails权威指南》是一本全面深入探讨Grails框架的专著,旨在帮助读者掌握这一强大的Web开发工具。Grails是一种基于Groovy语言的开源框架,它为构建现代、高效的应用程序提供了简洁高效的解决方案。本指南针对不同...

    grails-用户手册

    Grails,作为一个基于Groovy语言的开源Web应用框架,深受开发者喜爱,它简化了Java开发的复杂性,提供了强大的MVC(Model-View-Controller)架构,以及丰富的插件系统。这份用户手册将帮助你深入理解和高效使用...

    Eclipse下搭建Grails项目

    Grails是一个基于Groovy语言的开源Web应用框架,它简化了开发过程,尤其适合快速构建动态网站。在Eclipse中搭建Grails项目可能相对复杂,但通过以下步骤,即使是初学者也能顺利进行。 1. **Grails环境安装** - ...

    第一个grails程序

    在"第一个grails程序"中,我们通常会看到一个典型的Grails项目结构,包括以下几个关键部分: 1. **src/main/groovy**:这个目录存放所有Groovy源代码,包括应用程序的主要业务逻辑和控制器。 2. **src/main/...

    eclipse开发grails插件

    对于Grails开发,我们需要的是Eclipse中的Grails插件,它能够提供对Grails项目的创建、运行、调试等一系列功能。 **Grails**是基于Groovy语言的全栈式Web开发框架,它借鉴了Ruby on Rails的设计理念,提供了快速...

    grails中文入门简介

    Grails是一个基于Groovy语言的全栈框架,它遵循约定优于配置的原则,并且紧密集成Spring和Hibernate等流行的Java库,简化了开发流程。Grails在IT行业中尤其受到重视,因为它能够帮助开发者快速搭建并部署基于MVC模式...

    Grails中文参考手册

    Grails 插件系统是其强大功能之一,允许开发者复用和扩展已有功能。例如,有用于认证、缓存、邮件发送等的插件,可以快速集成到项目中。 **Grails Command Line Interface (CLI)** Grails 提供了一个强大的命令行...

    grails-2.4.4.zip

    Grails 的强大之处在于其丰富的插件库,如Spring Security用于安全控制,Hibernate Search提供全文搜索功能,以及各种用于支付、邮件发送、社交网络集成的插件,极大地扩展了框架的功能。 6. **IDE集成** ...

    grails框架

    grails的插件系统也是其亮点之一。首先,和rails,django等web框架类似,基于微内核的思想,插件(可重用模块)是框架的一等公民。grails除了核心模块以外的功能几乎都是通过插件方式实现的。实际上,一个grails插件...

    grails快速开发web

    #### 一、Grails 概述 Grails 是一种基于 Groovy 的开源应用框架,用于简化 Web 应用程序的开发过程。它采用约定优于配置的原则,这使得开发者可以更快地创建功能丰富的 Web 应用程序。Grails 的设计灵感来源于 ...

    Grails 中文参考手册

    《Grails 中文参考手册》是一本全面介绍Grails框架的指南,旨在帮助开发者快速上手并深入理解Grails的各个核心概念和技术。Grails是一个基于Groovy语言的开源Web应用框架,它提供了高效的开发环境和强大的功能,使得...

    grails 中文文档+grails-fckeditor-0.9.5.zip插件

    3. Convention over Configuration(CoC):Grails的核心理念之一就是“约定优于配置”,这意味着开发者在很多情况下不需要写大量的配置文件,框架会自动根据约定进行工作。 二、Grails中文文档的价值 1. 学习入口...

    grails login

    Grails是一个基于Java的开源Web应用程序框架,它使用Groovy语言进行开发,提供了高效、简洁的编程模型。在Grails中实现用户登录功能是构建任何Web应用的基础,它确保了数据的安全性和用户权限的管理。本示例将详细...

Global site tag (gtag.js) - Google Analytics