Last active
August 29, 2015 14:20
-
-
Save nobeans/fbe4d3684ed44e0aab0e to your computer and use it in GitHub Desktop.
Grails3で双方向1対1のドメインクラスの保存がrun-appしたときだけNPEになる事象
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{org.grails.orm.hibernate.GrailsHibernateTemplate$7@17518} | |
OK | |
2 | |
org.grails.orm.hibernate.AbstractHibernateGormInstanceApi$_performSave_closure3@27ba4c03 | |
3 | |
org.grails.orm.hibernate.validation.UniqueConstraint$2@40259e2 | |
OK | |
---------------------------------------------------------- | |
EntityIdentityInsertAction#preInsert() | |
size = 3 | |
{org.hibernate.cfg.beanvalidation.BeanValidationEventListener@12956} | |
{org.grails.orm.hibernate.support.ClosureEventTriggeringInterceptor@12966} | |
→拒否権発動! | |
{org.grails.orm.hibernate.support.ClosureEventTriggeringInterceptor$NullabilityCheckerPreInsertEventListener@12967} | |
↓ | |
{org.grails.orm.hibernate.support.ClosureEventTriggeringInterceptor@12966} | |
org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@7048535f: startup date [Tue Apr 28 14:14:19 JST 2015]; root of context hierarchy | |
size = 1 | |
"{org.grails.orm.hibernate.SessionFactoryProxy@13079}" -> "{org.grails.orm.hibernate.HibernateDatastore@13080}" | |
---------------------------------------------------------- | |
preInsertでの拒否権の発動が原因かと思ったが、それは二次災害であり、本来はpreInsert自体が呼ばれてはいけないことが分かった。 | |
それ以前のvalidateでNGになるので、preInsertが呼ばれる前に終わるのがただしい。 | |
Java8では、validateがなぜかスルーされてしまい、preInsertまでたどり着いてしまっている。 | |
---------------------------------------------------------- | |
起動時にAbstractMappingContext#addEntityValidatorで、各ドメインクラスのバリデータ情報を登録するが、ここでChannel, IrcbotState, Summaryがのvalidatorがnullで、結局登録されていないのが問題のようだ。 | |
Java7だと登録される。Java8だと登録されない。 | |
起動時にaddEntityValidatorは同一ドメインクラスに対して、2〜3回呼ばれている。Java7の場合も1回目の呼び出しは各ドメインクラスに対してすべてvalidatorはnullだが、2度目できちんと非null値が登録されている。Java8の場合は、2度目でChannel, Summary, IrcbotStateだけnull、それ以外は非nullになっている。 | |
未確認だったが、IrcbotStateもだめっぽい気がする。→なぜか問題ない... | |
---------------------------------------------------------- | |
実際にaddEntityValidatorを呼んでるところ | |
Java8 | |
GrailsDomainClassPersistentEntity | |
一通りドメインクラスを回るもvalidatorはすべてnull | |
AbstractHibernateGormEnhancer | |
Channel, IrcbotState, Summary | |
null | |
Irclog, Person, Role | |
HibernateDomainClassValidator | |
Java7 | |
GrailsDomainClassPersistentEntity | |
一通りドメインクラスを回るもvalidatorはすべてnull | |
AbstractHibernateGormEnhancer | |
Channel, IrcbotState, Summary, Irclog, Person, Role | |
HibernateDomainClassValidator | |
---------------------------------------------------------- | |
ドメインクラスのgetValidator()でnullになってる | |
Channel | |
DefaultGrailsDomainClass#getValidator() | |
これはsetValidator()で設定した値を返してるだけ | |
DefaultGrailsDomainClass#setValidator() | |
Java7 | |
↓から呼ばれてる | |
GrailsDomainClassValidator#setDomainClass() | |
↓sun.reflect.NativeMethodAcessImplを経由して呼ばれてる。怪しい? | |
Java8 | |
setValidator自体はすべて呼ばれている | |
つまりvalidatorフィールドはnullじゃないはずなのに... | |
Role, Irclog, PersonのsetValidator呼び出しと、Channel, Summary, IrcbotStateの呼び出しに少し時間のギャップがある | |
怪しい? | |
AbstractHibernateGormEnhancerを初期化した後に見つけてる?間に合ってない? | |
それっぽい。確かに間に合ってない。1回目にnullになった後、2回目でvalidator実装を見つける前に、AbstractHibernateGormEnhancerでdomainClass.validatorを参照 | |
---------------------------------------------------------- | |
ビーンの初期化順序が怪しいことが分かってきたのでもう一度確認してみる | |
Java8 | |
ビーンの初期化: grailsDomainClassMappingContext | |
GrailsDomainClassPersistentEntity | |
一通りドメインクラスを回るもvalidatorはすべてnull | |
ビーンの初期化: irclog.IrclogValidator | |
ビーンの初期化: irclog.PersonValidator | |
ビーンの初期化: irclog.RoleValidator | |
ビーンの初期化: org.grails.gorm.hibernate.internal.POST_INIT_BEAN-DEFAULT | |
AbstractHibernateGormEnhancer | |
Channel, IrcbotState, Summary | |
null | |
Irclog, Person, Role | |
HibernateDomainClassValidator | |
ビーンの初期化: irclog.IrcbotStateValidator | |
ビーンの初期化: irclog.SummaryValidator | |
ビーンの初期化: irclog.ChannelValidator | |
Java7 | |
ビーンの初期化: grailsDomainClassMappingContext | |
GrailsDomainClassPersistentEntity | |
一通りドメインクラスを回るもvalidatorはすべてnull | |
ビーンの初期化: irclog.ChannelValidator | |
ビーンの初期化: irclog.SummaryValidator | |
ビーンの初期化: irclog.RoleValidator | |
ビーンの初期化: irclog.IrcbotStateValidator | |
ビーンの初期化: org.grails.gorm.hibernate.internal.POST_INIT_BEAN-DEFAULT | |
AbstractHibernateGormEnhancer | |
Channel, IrcbotState, Summary, Role | |
HibernateDomainClassValidator | |
Irclog, Person | |
null | |
ビーンの初期化: irclog.PersonValidator | |
ビーンの初期化: irclog.IrclogValidator | |
えっ | |
これ、逆にJava7だとPersonやIrclogのsaveでぬるぽになるっていうこと? | |
やってみたら...ぬるぽ! | |
つまり、Java7と8で出方は違うけど、両方ともアウトなバグがある、ということ? |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment