[英]Grails : 'methodInvocation' error code when validate domain object
Since two weeks, a wild issue appears ! 两个星期以来,出现了一个大问题! It comes only in production (not in dev, integration, preproduction modes) and after hours....
它仅在生产中出现(不在开发,集成,预生产模式中)和下班后出现。
Symptoms : once "something" happens, users cannot sign up anymore. 症状:一旦发生“某事”,用户将无法注册。 After days and days of investigations, I have no clue how to reproduce neither where come this issue.
经过数天的调查,我不知道该如何复制这个问题。 For now, we have the ugly workaround to restart tomcat instances, but this is VERY ugly.
目前,我们有丑陋的解决方法来重新启动tomcat实例,但这非常丑陋。
For information, differences between two deliveries doesn't touch around the sign up process. 有关信息,两个交付之间的差异与注册过程无关。
Here what I think is relevant : 我认为这是相关的:
Domain : 域:
class UserAccount implements Serializable {
static transients = ['tokenLogin']
String email
String pwd
Date creationDate = new Date()
String tokenLogin
//[skip] dozen of other attributes
static constraints = {
email(matches:EmailRegexp,blank:false)
pwd(blank:false)
tokenLogin(editable:false)
}
public void setEmail(String email) {
this.email = email
authId = authenticationChannel.getUsername(email)
// We must recalculate token login
this.tokenLogin = generateTokenLogin(email, creationDate, pwd)
}
public void setPwd(String pwd) {
this.pwd = pwd
// We must recalculate token login
this.tokenLogin = generateTokenLogin(email, creationDate, pwd)
}
public static String generateTokenLogin(String email, Date creationDate, String pwd) {
// work well
// even tested when return null or with NPE in it and does not produce the same log
generated = // work with MessageDigest, MD5, salt, etc. (not disclosed, because we are currently under security audit)
return generated;
}
}
Controller : 控制器:
def saveAccount = {
def user = new UserAccount(email: params.email?.trim(), pwd: params.pwd) // More parameters, but here what is relevant
user.validate()
if(user.hasErrors()) log.info("${user.errors}") // added since the issue appears
// Other verification (unicity, clear password verification, etc.)
// Password encryption
// user.save()
}
Output log : 输出日志:
2013-06-03 15:37:32,165 [TP-Processor46] INFO controller.UserAccountController - org.springframework.validation.BeanPropertyBindingResult: 1 errors
Field error in object 'domain.UserAccount' on field 'pwd': rejected value [foobar]; codes [methodInvocation.domain.UserAccount.pwd,methodInvocation.pwd,methodInvocation.java.lang.String,methodInvocation]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [domain.UserAccount.pwd,pwd]; arguments []; default message [pwd]]; default message [Property 'pwd' threw exception; nested exception is java.lang.NullPointerException]
Questions : 问题:
pwd
or email
field, never for others. pwd
或email
字段,从未为其他人使用。 MethodInvocationException
is thrown when BeanWrapperImpl.setPropertyValue
catch an exception) BeanWrapperImpl.setPropertyValue
捕获异常时,抛出MethodInvocationException
) Informations : 信息:
In start.sh
(tomcat options) 在
start.sh
(tomcat选项)
JAVA_OPTS="-Dapp=prod -Xms1024m -Xmx1024m -XX:MaxPermSize=256m \
-Dfile.encoding=UTF-8 -XX:+UseParNewGC -XX:+UseConcMarkSweepGC \
-XX:+CMSClassUnloadingEnabled -XX:+CMSPermGenSweepingEnabled \
-XX:+HeapDumpOnOutOfMemoryError \
-Xloggc:/path/to/gc.log"
Edit : We change and compile spring-context.jar
to be able to see a StackTrace. 编辑:我们更改并编译
spring-context.jar
才能看到StackTrace。 and we get this one : 我们得到这个:
org.springframework.beans.PropertyBatchUpdateException; nested PropertyAccessException details (1) are:
PropertyAccessException 1:
org.springframework.beans.MethodInvocationException: Property 'pwd' threw exception; nested exception is java.lang.NullPointerException
at org.springframework.beans.BeanWrapperImpl.setPropertyValue(BeanWrapperImpl.java:1127)
at org.springframework.beans.BeanWrapperImpl.setPropertyValue(BeanWrapperImpl.java:900)
at org.springframework.beans.AbstractPropertyAccessor.setPropertyValues(AbstractPropertyAccessor.java:76)
at org.springframework.validation.DataBinder.applyPropertyValues(DataBinder.java:673)
at org.springframework.validation.DataBinder.doBind(DataBinder.java:569)
at org.springframework.web.bind.WebDataBinder.doBind(WebDataBinder.java:191)
[snip]
Caused by: java.lang.NullPointerException
at org.codehaus.groovy.runtime.callsite.PojoMetaClassSite.checkCall(PojoMetaClassSite.java:54)
at org.codehaus.groovy.runtime.callsite.PojoMetaClassSite.call(PojoMetaClassSite.java:42)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:124)
at domain.UserAccount.generateTokenLogin(UserAccount.groovy:369)
at domain.UserAccount$generateTokenLogin.callStatic(Unknown Source)
at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCallStatic(CallSiteArray.java:48)
at domain.UserAccount$generateTokenLogin.callStatic(Unknown Source)
at domain.UserAccount.setPwd(UserAccount.groovy:184)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.springframework.beans.BeanWrapperImpl.setPropertyValue(BeanWrapperImpl.java:1114)
The root cause is that exists an creationDate
that might be null
on some weird conditions. 根本原因是存在一个
creationDate
,在某些怪异的条件下它可能为null
。 I guess the solution is not to call generateTokenLogin()
in setters (and only in getters). 我猜想解决方案不是在setter中(仅在getter中)调用
generateTokenLogin()
)。
I cannot explain why we did not have this issue before (no recent upgrade, etc.) 我无法解释为什么以前没有这个问题(最近没有升级等)
It sounds like once this happens it isn't fixed without a restart. 听起来好像一旦发生这种情况,就必须重新启动才能解决。 I would look at the permgen size for your application.
我会看看您的应用程序的permgen大小。 If it works in every environment expect production it might be a memory issues.
如果它在每种环境下都能正常生产,则可能是内存问题。
Easy way to test is add 200megs or so to start. 测试的简单方法是添加200兆个左右开始。
just a wild guess - when you override a setter, you shouldn't set the value of that field inside this setter, because it's a kind of recursion, or at least unpredicted behavior (like this) could be expected, maybe try using raw field access operator: 只是一个疯狂的猜测-当您覆盖设置器时,不应在此设置器中设置该字段的值,因为这是一种递归操作,或者至少会发生无法预料的行为(例如这样),请尝试使用原始字段访问运算符:
public void setPwd(String pwd) {
this.@pwd = pwd
// We must recalculate token login
this.tokenLogin = generateTokenLogin(email, pwd)
}
the same goes for email
field/setter email
字段/设置者也是如此
Is your pre-prod server exactly the same as your prod server ? 生产前的服务器与生产前的服务器完全相同吗? Which are the minors modifications you make, are you sur there is no impact ?
您对未成年人进行了哪些修改,对您没有任何影响?
It could be the war generated which contains errors, did you try a rollback on your modifications ? 可能是产生了包含错误的战争,您是否尝试对所做的修改进行回滚?
Mayby you could take your prod war and put it into your pre-prod env to reproduce the issue. 也许您可以进行产品战争并将其放入产品前环境中以重现该问题。
Is there a recent update from a plugin, grails version, or whatever in your dependencies ? 是否有插件,grails版本或您的依赖项中的任何最新更新?
Not answering your question, but peraps I can give you investigations ideas. 我没有回答您的问题,但是可以为您提供调查思路。
Snite ite
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.