Create
cancel
Showing results for 
Search instead for 
Did you mean: 
Sign up Log in

Scripted groovy custom field: javax.script.ScriptException: java.lang.NullPointerException in jira logs after reindexing

Emmanuel Boukandoura January 29, 2014

Hi Everyone,

I've created a groovy scripted field whose script sums the amount of estimated of hour in the sub-tasks of a story:

import com.atlassian.jira.ComponentManager
import com.atlassian.jira.issue.Issue

def componentManager = ComponentManager.getInstance()
def ssa = componentManager.getSubTaskManager().getSubTaskObjects(issue)//.toArray()
def int size = ssa.size()
if (size > 0){
def double sum = 0
for (int i = 0; i < size; i++){
sum = sum + ssa[i].getEstimate()
}
def double res = sum / 3600
return res
} else {
return null
}

It works fine and nothing appreas in the logs but as soon as I start a reindexing of the server, this error message is tracked in the logs:

/secure/admin/jira/IndexReIndex.jspa [onresolve.jira.groovy.GroovyCustomField] javax.script.ScriptException: java.lang.NullPointerException
javax.script.ScriptException: javax.script.ScriptException: java.lang.NullPointerException
        at org.codehaus.groovy.jsr223.GroovyScriptEngineImpl.eval(GroovyScriptEngineImpl.java:117)
        at javax.script.AbstractScriptEngine.eval(AbstractScriptEngine.java:233)
        at javax.script.ScriptEngine$eval.call(Unknown Source)
        at com.onresolve.jira.groovy.GroovyCustomField.getValueFromIssue(GroovyCustomField.groovy:160)
        at com.atlassian.jira.issue.fields.CustomFieldImpl.getValue(CustomFieldImpl.java:395)
        at com.atlassian.jira.issue.index.indexers.impl.NumberCustomFieldIndexer.addDocumentFields(NumberCustomFieldIndexer.java:41)
        at com.atlassian.jira.issue.index.indexers.impl.NumberCustomFieldIndexer.addDocumentFieldsNotSearchable(NumberCustomFieldIndexer.java:36)
        at com.atlassian.jira.issue.index.indexers.impl.AbstractCustomFieldIndexer.addIndex(AbstractCustomFieldIndexer.java:50)
        at com.atlassian.jira.issue.index.IssueDocument.getDocument(IssueDocument.java:41)
        at com.atlassian.jira.issue.index.DefaultIssueDocumentFactory.get(DefaultIssueDocumentFactory.java:15)
        at com.atlassian.jira.issue.index.DefaultIssueDocumentFactory.get(DefaultIssueDocumentFactory.java:11)
        at com.atlassian.jira.issue.index.DefaultIssueIndexer$IssueLockDocumentCreationStrategy$2.get(DefaultIssueIndexer.java:598)
        at com.atlassian.jira.issue.index.DefaultIssueIndexer$IssueLockDocumentCreationStrategy$2.get(DefaultIssueIndexer.java:593)
        at com.atlassian.util.concurrent.ManagedLocks$ManagedLockImpl.withLock(ManagedLocks.java:303)
        at com.atlassian.jira.issue.index.DefaultIssueIndexer$IssueLockDocumentCreationStrategy.get(DefaultIssueIndexer.java:592)
        at com.atlassian.jira.issue.index.DefaultIssueIndexer$2.perform(DefaultIssueIndexer.java:158)
        at com.atlassian.jira.issue.index.DefaultIssueIndexer$4$1.get(DefaultIssueIndexer.java:284)
        at com.atlassian.jira.issue.index.DefaultIssueIndexer$4$1.get(DefaultIssueIndexer.java:280)
        at com.atlassian.jira.index.SimpleIndexingStrategy.get(SimpleIndexingStrategy.java:9)
        at com.atlassian.jira.index.SimpleIndexingStrategy.get(SimpleIndexingStrategy.java:5)
        at com.atlassian.jira.issue.index.DefaultIssueIndexer$4.consume(DefaultIssueIndexer.java:279)
        at com.atlassian.jira.issue.index.DefaultIssueIndexer$4.consume(DefaultIssueIndexer.java:272)
        at com.atlassian.jira.issue.util.DatabaseIssuesIterable.foreach(DatabaseIssuesIterable.java:66)
        at com.atlassian.jira.issue.index.DefaultIssueIndexer.perform(DefaultIssueIndexer.java:271)
        at com.atlassian.jira.issue.index.DefaultIssueIndexer.reindexIssues(DefaultIssueIndexer.java:153)
        at com.atlassian.jira.issue.index.DefaultIndexManager.doBackgroundReindex(DefaultIndexManager.java:801)
        at com.atlassian.jira.issue.index.DefaultIndexManager.reIndexAll(DefaultIndexManager.java:320)
        at com.atlassian.jira.issue.index.DefaultIndexManager.reIndexAllIssuesInBackground(DefaultIndexManager.java:367)  <+3> (NativeMethodAccessorImpl.java:57) (DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:606)
        at com.atlassian.util.profiling.object.ObjectProfiler.profiledInvoke(ObjectProfiler.java:83)
        at com.atlassian.jira.config.component.SwitchingInvocationHandler.invoke(SwitchingInvocationHandler.java:28)
        at com.sun.proxy.$Proxy124.reIndexAllIssuesInBackground(Unknown Source)
        at com.atlassian.jira.util.index.CompositeIndexLifecycleManager.reIndexAllIssuesInBackground(CompositeIndexLifecycleManager.java:83)
        at com.atlassian.jira.web.action.admin.index.ReIndexBackgroundIndexerCommand.doReindex(ReIndexBackgroundIndexerCommand.java:27)
        at com.atlassian.jira.web.action.admin.index.AbstractAsyncIndexerCommand.call(AbstractAsyncIndexerCommand.java:54)
        at com.atlassian.jira.web.action.admin.index.ReIndexBackgroundIndexerCommand.call(ReIndexBackgroundIndexerCommand.java:15)
        at com.atlassian.jira.web.action.admin.index.AbstractAsyncIndexerCommand.call(AbstractAsyncIndexerCommand.java:23)
        at com.atlassian.jira.task.TaskManagerImpl$TaskCallableDecorator.call(TaskManagerImpl.java:365)
        at java.util.concurrent.FutureTask.run(FutureTask.java:262)
        at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:471)
        at java.util.concurrent.FutureTask.run(FutureTask.java:262)
        at com.atlassian.jira.task.ForkedThreadExecutor$ForkedRunnableDecorator.run(ForkedThreadExecutor.java:249)
        at java.lang.Thread.run(Thread.java:744)
Caused by: javax.script.ScriptException: java.lang.NullPointerException
        at org.codehaus.groovy.jsr223.GroovyScriptEngineImpl.eval(GroovyScriptEngineImpl.java:318)
        at org.codehaus.groovy.jsr223.GroovyScriptEngineImpl.eval(GroovyScriptEngineImpl.java:111)
        ... 45 more
Caused by: java.lang.NullPointerException
        at org.codehaus.groovy.runtime.dgmimpl.NumberNumberPlus$DoubleLong.call(NumberNumberPlus.java:153)
        at org.codehaus.groovy.jsr223.GroovyScriptEngineImpl.eval(GroovyScriptEngineImpl.java:315)
        ... 46 more

I must add that the reindexing process reaches its end though.

Could anyone help by suggesting any element I should add to the script to make it safer?

Many thanks,

Emmanuel

2 answers

1 accepted

Comments for this post are closed

Community moderators have prevented the ability to post new answers.

Post a new question

0 votes
Answer accepted
Henning Tietgens
Rising Star
Rising Star
Rising Stars are recognized for providing high-quality answers to other users. Rising Stars receive a certificate of achievement and are on the path to becoming Community Leaders.
January 29, 2014

In scripted fields you should assume that every field value could be null. You should check every possible null value.

sum = sum + ssa[i].getEstimate()?:0

could fix the error.

Henning Tietgens
Rising Star
Rising Star
Rising Stars are recognized for providing high-quality answers to other users. Rising Stars receive a certificate of achievement and are on the path to becoming Community Leaders.
January 29, 2014

Maybe

def int size = ssa?.size()?:0
is another good idea.
Emmanuel Boukandoura January 29, 2014

Thanks for your reply, I made the change but I'm still facing this issue

Henning Tietgens
Rising Star
Rising Star
Rising Stars are recognized for providing high-quality answers to other users. Rising Stars receive a certificate of achievement and are on the path to becoming Community Leaders.
January 29, 2014

Could you try this?

import com.atlassian.jira.component.ComponentAccessor

def sum = 0
ComponentAccessor.getSubTaskManager().getSubTaskObjects(issue)?.each{ subtask ->
    sum += (subtask?.getEstimate())?:0        
}
return (sum/3600) as Double

Emmanuel Boukandoura January 29, 2014

Definitely nicer than my prehistoric version... and removing every error from the logs.

I've just added if (sum !=0) {return (sum/3600) as Double} else return null to ensure this field won't show up on issues with no sub-tasks.

Thanks a lot!

0 votes
Tamir Lavi January 29, 2014

I am facing similar issues for long time now.

I decided to add try/catch on every scripted field.

I know it's not "best practice" but it may help to clear the logs when the exceptions are hard to find.

In case of exception I return "error" for text fields so I wont loss trace, or null in others field types.

JamieA
Rising Star
Rising Star
Rising Stars are recognized for providing high-quality answers to other users. Rising Stars receive a certificate of achievement and are on the path to becoming Community Leaders.
January 29, 2014

try/catch will get you indexing again, but if there are exceptions you should look at them, rather than letting them fill your logs!

As Henning said, think about every eventuality. However I wouldn't go so far as checking whether issue.subTasks() is null etc... it should not be, according to the API.

Tamir Lavi February 1, 2014

try/catch will eliminate the exceptions from your logs, since its been "handeled" - and therefor not raised to caller of the script.

Still - ignoring it is not good practice!
But when you have lots of issues and complicated script fields - it could be handy.

For example - if you have problems in you production environment - you can use try/catch to eliminate the problem from the logs, while debuging the problem in a dev env.

TAGS
AUG Leaders

Atlassian Community Events