`
hax
  • 浏览: 951288 次
  • 性别: 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 Grails Grails Grails Grails

    Grails开发之(Rest教程).pdf

    Grails开发之(Rest教程).pdf

    Grails开发之(Rest教程).docx

    Grails开发之(Rest教程).docx

    Grails权威指南 Grails权威指南

    Grails权威指南Grails权威指南Grails权威指南Grails权威指南Grails权威指南Grails权威指南

    Groovy轻松入门——Grails实战基础篇

    在学习任何东西之前,最重要的是培养兴趣,Groovy世界最耀眼的技术之一--Grails相信大家早已耳闻,我将通过Grails实战系列文章 向您展现Grails的迷人风采,使您感受到Grails的魅力,以至疯狂地爱上Grails,并坠入...

    grails框架

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

    Eclipse下搭建Grails项目

    Grails项目的应用越来越多,而对于初学者来说,在Eclipse下搭建Grails项目是一个难题,这个文档将教会你如何搭建Grails项目,希望对你有所帮助。

    Grails1.1中文文档

    Grails建立在这些概念之上,它极大地降低了在Java平台上建立Web应用的复杂性。与那些框架不同的是,Grails是构建在现有的像Spring、Hibernate这样的Java技术之上。 Grails是个一栈式开发框架,它尝试通过核心技术...

    Grails入门指南 -- 针对grails1.0.4更新

    Grails入门指南中文pdf -- 针对grails1.0.4更新,附加idea8 开发grails的流程

    grails+Xfire webservice

    grails+Xfire webservice

    grails

    grails-2.1.zip.001

    grails入门经典

    grails grails入门经典 grails入门 grails例子 grails资料 通过自学一点点积累起来的,相信对你有帮助的。

    grails 1.0.4

    Grails尽量为更多现有的Java项目创建一个全面的框架(不仅局限于视图处理),这和当前一些Java框架提供给用户的一种AnemicAPI形成了明显的对比。Grails的出现并不是偶然的,而是随着Web应用的日趋复杂及Web2.0和Ajax...

    Grails中文参考手册

    Grails 中文 参考手册

    Grails 教程

    像Rails,Django和TurboGears这样的动态框架在Web开发领域开辟了一条新的道路,Grails基于这些概念之上,采用动态方法减小了Java平台上进行Web开发的复杂度,不过与那些框架不同的是,Grails是构建在Spring和...

    Grails1.1中文文档(CHM)

    Grails1.1最新 中文 文档 当今的Java Web开发技术...Grails建立在这些概念之上,它极大地降低了在Java平台上建立Web应用的复杂性。与那些框架不同的是,Grails是构建在现有的像Spring、Hibernate这样的Java技术之上。

    grails开发环境配置及应用开发

    详细讲解grails开发环境配置。 详细讲解grails连接mysql数据库,crud开发

    grails3.2.8-01

    grails3.2.8 part1

    Grails探索之访问存储过程及其事务控制

    Grails探索之访问存储过程及其事务控制 Grails探索系列 来自IBM

Global site tag (gtag.js) - Google Analytics