一个 GORM 定义错误,关于集合属性的排序设置

14 篇文章 0 订阅

当一个 Domain Class 有一个集合属性时,我们可以指定集合的排序方法。
示例代码如下:

class Airport {
    ...
    static hasMany = [flights: Flight]

    static mapping = {
        flights sort: 'number', order: 'desc'
    }
}

上面的代码就可以让 机场(Airport) 的 航班(Flight) 按照 number 倒序排列。

这里需要注意,number 属性是 Flight 类的一个属性而不是 Airport 的属性,如果设置了错误的属性,将导致程序在做集成测试时启动失败。

今天就遇到了这个错误,在执行集成测试时报告错误:

java.lang.IllegalStateException: Failed to load ApplicationContext

检查异常堆栈日志

...
...省略大量关系不大的异常信息...
...
Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.grails.orm.hibernate.HibernateDatastore]: Constructor threw exception; nested exception is java.lang.NullPointerException
	at org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:184)
	at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:117)
	at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:300)
	... 85 common frames omitted
Caused by: java.lang.NullPointerException: null
	at org.grails.orm.hibernate.cfg.GrailsDomainBinder.bindCollectionSecondPass(GrailsDomainBinder.java:368)
	at org.grails.orm.hibernate.cfg.GrailsDomainBinder.bindListSecondPass(GrailsDomainBinder.java:265)
	at org.grails.orm.hibernate.cfg.GrailsDomainBinder$ListSecondPass.doSecondPass(GrailsDomainBinder.java:3426)
	at org.hibernate.boot.internal.InFlightMetadataCollectorImpl.processSecondPasses(InFlightMetadataCollectorImpl.java:1684)
	at org.hibernate.boot.internal.InFlightMetadataCollectorImpl.processSecondPasses(InFlightMetadataCollectorImpl.java:1652)
	at org.hibernate.boot.model.process.spi.MetadataBuildingProcess.complete(MetadataBuildingProcess.java:287)
	at org.hibernate.boot.model.process.spi.MetadataBuildingProcess.build(MetadataBuildingProcess.java:84)
	at org.hibernate.boot.internal.MetadataBuilderImpl.build(MetadataBuilderImpl.java:474)
	at org.hibernate.boot.internal.MetadataBuilderImpl.build(MetadataBuilderImpl.java:85)
	at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:689)
	at org.grails.orm.hibernate.cfg.HibernateMappingContextConfiguration.buildSessionFactory(HibernateMappingContextConfiguration.java:287)
	at org.grails.orm.hibernate.connections.HibernateConnectionSourceFactory.create(HibernateConnectionSourceFactory.java:86)
	at org.grails.orm.hibernate.connections.AbstractHibernateConnectionSourceFactory.create(AbstractHibernateConnectionSourceFactory.java:39)
	at org.grails.orm.hibernate.connections.AbstractHibernateConnectionSourceFactory.create(AbstractHibernateConnectionSourceFactory.java:23)
	at org.grails.datastore.mapping.core.connections.AbstractConnectionSourceFactory.create(AbstractConnectionSourceFactory.java:64)
	at org.grails.datastore.mapping.core.connections.AbstractConnectionSourceFactory.create(AbstractConnectionSourceFactory.java:52)
	at org.grails.datastore.mapping.core.connections.ConnectionSourcesInitializer.create(ConnectionSourcesInitializer.groovy:24)
	at org.grails.orm.hibernate.HibernateDatastore.<init>(HibernateDatastore.java:200)
	at sun.reflect.GeneratedConstructorAccessor73.newInstance(Unknown Source)
	at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
	at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
	at org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:172)
	... 87 common frames omitted

发现是NPE

at org.grails.orm.hibernate.cfg.GrailsDomainBinder.bindCollectionSecondPass(GrailsDomainBinder.java:368)

查看导致NPE的代码片段

protected void bindCollectionSecondPass(ToMany property, InFlightMetadataCollector mappings,
                                        Map<?, ?> persistentClasses, Collection collection, 
                                        String sessionFactoryBeanName) {
......
	if (associatedClass != null) {
	    collection.setOrderBy(buildOrderByClause(propertyToSortBy.getName(), associatedClass, collection.getRole(),
	            propConfig.getOrder() != null ? propConfig.getOrder() : "asc"));
	}
......
}

通过设置断点,发现是 propertyToSortBy 为 null 了。

检查导致错误的domain class代码

class Campaign {
	List<PrizeSetting> prizeSettings
    static mapping = {
        campaignStatus enumType: "identity"
        // 指定 奖项 的排序规则
        prizeSettings sort: 'position', order: 'desc'
    }
}

仔细检查,发现 PrizeSetting 没有属性 position,应该排序的字段是 prizeLevel。

修改为正确代码

    static mapping = {
        campaignStatus enumType: "identity"
        // 指定 奖项 的排序规则
        prizeSettings sort: 'prizeLevel', order: 'desc'
    }

问题解决!

参考文档:

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值