It's not the same without you

Join the community to find out what other Atlassian users are discussing, debating and creating.

Atlassian Community Hero Image Collage

How do I resolve java.lang.ClassNotFoundException error for HistoricalEstimateStatisticValueResolver

Erik Saline Aug 31, 2017

I am creating a custom REST Endpoint using the AWESOME ScriptRunner plugin but I am running into a ClassNotFoundException.

I am trying to extend the current JIRA Velocity REST End Point to return more than 7 sprints.  I was able to find the current Velocity REST End Point and find where the Sprint Count is hard coded to 7.

Any help to resolve the CLASSNotFoundException would be appreciated! 



2017-08-31 15:31:38,501 ERROR [common.UserCustomScriptEndpoint]: ************************************************************************************* 2017-08-31 15:31:38,502 ERROR [common.UserCustomScriptEndpoint]: Script endpoint failed on method: GET getVelocity java.lang.NoClassDefFoundError: com/atlassian/greenhopper/web/rapid/issue/statistics/HistoricalEstimateStatisticValueResolver at atlassian.jira.scriptRestPoints.getVelocity$_run_closure1.doCall(getVelocity.groovy:120) at com.onresolve.scriptrunner.runner.rest.common.UserCustomScriptEndpoint.doEndpoint(UserCustomScriptEndpoint.groovy:312) at com.onresolve.scriptrunner.runner.rest.common.UserCustomScriptEndpoint.getUserEndpoint(UserCustomScriptEndpoint.groovy:195) Caused by: java.lang.ClassNotFoundException: com.atlassian.greenhopper.web.rapid.issue.statistics.HistoricalEstimateStatisticValueResolver ... 3 more

 

package atlassian.jira.scriptRestPoints

import com.atlassian.greenhopper.model.rapid.RapidView
import com.atlassian.greenhopper.model.rapid.StatisticsField
import com.atlassian.greenhopper.service.ServiceOutcome
import com.atlassian.greenhopper.service.ServiceOutcomeImpl
import com.atlassian.greenhopper.service.rapid.RapidViewQueryService
import com.atlassian.greenhopper.service.rapid.view.ColumnService
import com.atlassian.greenhopper.service.rapid.view.RapidViewService
import com.atlassian.greenhopper.service.rapid.view.statistics.EstimateStatisticService
import com.atlassian.greenhopper.service.sprint.Sprint
import com.atlassian.greenhopper.service.sprint.SprintQueryService
import com.atlassian.greenhopper.web.rapid.chart.SprintBurndownModelFactory
import com.atlassian.greenhopper.web.rapid.chart.VelocityChartModel
import com.atlassian.greenhopper.web.rapid.chart.VelocityChartModelFactory
import com.atlassian.greenhopper.web.rapid.chart.VelocityStatEntryFactory
import com.atlassian.greenhopper.web.rapid.issue.statistics.HistoricalEstimateStatisticValueResolver
import com.atlassian.greenhopper.web.rapid.issue.statistics.StatisticValueResolverFactory
import com.atlassian.greenhopper.web.rapid.sprint.SprintEntryFactory
import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.issue.status.Status
import com.atlassian.jira.user.ApplicationUser
import com.atlassian.query.Query
import com.atlassian.sal.api.user.UserManager
import com.atlassian.sal.api.user.UserProfile
import com.onresolve.scriptrunner.runner.rest.common.CustomEndpointDelegate
import groovy.json.JsonBuilder
import groovy.transform.BaseScript
import com.onresolve.scriptrunner.runner.customisers.JiraAgileBean
import com.onresolve.scriptrunner.runner.customisers.WithPlugin

import javax.servlet.http.HttpServletRequest
import javax.ws.rs.core.MultivaluedMap
import javax.ws.rs.core.Response

@BaseScript CustomEndpointDelegate delegate

@WithPlugin("com.pyxis.greenhopper.jira")

@JiraAgileBean
RapidViewService rapidViewService

@JiraAgileBean
RapidViewQueryService rapidViewQueryService

@JiraAgileBean
EstimateStatisticService estimateStatisticService

@JiraAgileBean
SprintQueryService sprintQueryService

@JiraAgileBean
SprintBurndownModelFactory sprintBurndownModelFactory

@JiraAgileBean
SprintEntryFactory sprintEntryFactory

@JiraAgileBean
StatisticValueResolverFactory statisticValueResolverFactory

@JiraAgileBean
ColumnService columnService

com.atlassian.sal.api.user.UserManager userManager = ComponentAccessor.getOSGiComponentInstanceOfType(UserManager)
com.atlassian.jira.user.util.UserManager jiraUserManager = ComponentAccessor.getUserManager()

getVelocity(httpMethod: "GET", groups: ["jira-users"]) {
MultivaluedMap queryParams, String body, HttpServletRequest request ->

UserProfile userProfile = userManager.getRemoteUser(request)

ApplicationUser user = jiraUserManager.getUserByName(userProfile.username)

String rapidViewId = queryParams.getFirst("rapidViewId")

String sprintCount = queryParams.getFirst("sprintCount")

ServiceOutcome rapidView = rapidViewService.getRapidView(user, rapidViewId.toLong())

ServiceOutcome rapidViewQuery = rapidViewQueryService.getRapidViewQuery(user, (RapidView) rapidView.getValue())

log.info("Starting getVelocity.groovy script, BoardId " + rapidViewId + " SprintCount " + sprintCount)

if (!rapidViewQuery.isValid()) {
return ServiceOutcomeImpl.error(rapidViewQuery)
} else {
ServiceOutcome estimateStatistic = estimateStatisticService.getEstimateStatisticStrict((RapidView) rapidView.getValue())
if (!estimateStatistic.isValid()) {
return ServiceOutcomeImpl.error(estimateStatistic)
} else {
ServiceOutcome sprints = sprintQueryService.getClosedSprints(user, (Query) rapidViewQuery.getValue())
if (!sprints.isValid()) {
return ServiceOutcomeImpl.error(sprints)
} else {

// Create a list of Mapped Status
Set<Status> mappedStatues = columnService.getMappedStatuses((RapidView) rapidView.getValue())

// Create a list of Mapped Status Ids from Mapped Statuses
ArrayList mappedStatusIds = new ArrayList()

for (Status status : mappedStatues) {
mappedStatusIds.add(status.getId())
}

List closedSprints = (List) sprints.getValue()
Collections.sort(closedSprints, new VelocityChartModelFactory.SprintComparator())
VelocityChartModel model = new VelocityChartModel()
int numSprints = closedSprints.size() > sprintCount.toInteger() ? sprintCount.toInteger() : closedSprints.size()
Iterator var10 = closedSprints.subList(0, numSprints).iterator()

while (var10.hasNext()) {
Sprint sprint = (Sprint) var10.next()
ServiceOutcome historyData = sprintBurndownModelFactory.getBurndownChangesForSprint(user, (RapidView) rapidView.getValue(), sprint)
if (!historyData.isValid()) {
return ServiceOutcomeImpl.error(historyData)
}

HistoricalEstimateStatisticValueResolver valueResolver = statisticValueResolverFactory.forHistoricalEstimateStatisticValue((StatisticsField) estimateStatistic.getValue(), sprint, (Map) historyData.getValue(), mappedStatusIds)
model.sprints.add(sprintEntryFactory.newBaseTransformer(user).apply(sprint))
VelocityStatEntryFactory velocityStatEntryFactory = new VelocityStatEntryFactory(((Map) historyData.getValue()).keySet(), valueResolver)
model.velocityStatEntries.put(sprint.getId(), velocityStatEntryFactory.getVelocityStatEntry())
}

return ServiceOutcomeImpl.ok(model)
}
}
}

return Response.ok(new JsonBuilder().toString()).build()
}

 

1 answer

1 vote

Hi Erik.

May I recommend that when using groovy and defining classes, if you are not using any of their methods, you use the keyword "def" rather than the type. It really helps with dependency problems sometimes.

In this case you don't even need to have the class imported, since your object isn't being called at all, and it could be resolved dynamically.

Can you try and see if this works?

package atlassian.jira.scriptRestPoints


import com.atlassian.greenhopper.model.rapid.RapidView
import com.atlassian.greenhopper.model.rapid.StatisticsField
import com.atlassian.greenhopper.service.ServiceOutcome
import com.atlassian.greenhopper.service.ServiceOutcomeImpl
import com.atlassian.greenhopper.service.rapid.RapidViewQueryService
import com.atlassian.greenhopper.service.rapid.view.ColumnService
import com.atlassian.greenhopper.service.rapid.view.RapidViewService
import com.atlassian.greenhopper.service.rapid.view.statistics.EstimateStatisticService
import com.atlassian.greenhopper.service.sprint.Sprint
import com.atlassian.greenhopper.service.sprint.SprintQueryService
import com.atlassian.greenhopper.web.rapid.chart.SprintBurndownModelFactory
import com.atlassian.greenhopper.web.rapid.chart.VelocityChartModel
import com.atlassian.greenhopper.web.rapid.chart.VelocityChartModelFactory
import com.atlassian.greenhopper.web.rapid.chart.VelocityStatEntryFactory
import com.atlassian.greenhopper.web.rapid.issue.statistics.StatisticValueResolverFactory
import com.atlassian.greenhopper.web.rapid.sprint.SprintEntryFactory
import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.issue.status.Status
import com.atlassian.jira.user.ApplicationUser
import com.atlassian.query.Query
import com.atlassian.sal.api.user.UserManager
import com.atlassian.sal.api.user.UserProfile
import com.onresolve.scriptrunner.runner.customisers.JiraAgileBean
import com.onresolve.scriptrunner.runner.customisers.WithPlugin
import com.onresolve.scriptrunner.runner.rest.common.CustomEndpointDelegate
import groovy.json.JsonBuilder
import groovy.transform.BaseScript

import javax.servlet.http.HttpServletRequest
import javax.ws.rs.core.MultivaluedMap
import javax.ws.rs.core.Response

@BaseScript CustomEndpointDelegate delegate

@WithPlugin("com.pyxis.greenhopper.jira")

@JiraAgileBean
RapidViewService rapidViewService

@JiraAgileBean
RapidViewQueryService rapidViewQueryService

@JiraAgileBean
EstimateStatisticService estimateStatisticService

@JiraAgileBean
SprintQueryService sprintQueryService

@JiraAgileBean
SprintBurndownModelFactory sprintBurndownModelFactory

@JiraAgileBean
SprintEntryFactory sprintEntryFactory

@JiraAgileBean
StatisticValueResolverFactory statisticValueResolverFactory

@JiraAgileBean
ColumnService columnService

com.atlassian.sal.api.user.UserManager userManager = ComponentAccessor.getOSGiComponentInstanceOfType(UserManager)
com.atlassian.jira.user.util.UserManager jiraUserManager = ComponentAccessor.getUserManager()

getVelocity(httpMethod: "GET", groups: ["jira-users"]) {
MultivaluedMap queryParams, String body, HttpServletRequest request ->

UserProfile userProfile = userManager.getRemoteUser(request)

ApplicationUser user = jiraUserManager.getUserByName(userProfile.username)

String rapidViewId = queryParams.getFirst("rapidViewId")

String sprintCount = queryParams.getFirst("sprintCount")

ServiceOutcome rapidView = rapidViewService.getRapidView(user, rapidViewId.toLong())

ServiceOutcome rapidViewQuery = rapidViewQueryService.getRapidViewQuery(user, (RapidView) rapidView.getValue())

log.info("Starting getVelocity.groovy script, BoardId " + rapidViewId + " SprintCount " + sprintCount)

if (!rapidViewQuery.isValid()) {
return ServiceOutcomeImpl.error(rapidViewQuery)
} else {
ServiceOutcome estimateStatistic = estimateStatisticService.getEstimateStatisticStrict((RapidView) rapidView.getValue())
if (!estimateStatistic.isValid()) {
return ServiceOutcomeImpl.error(estimateStatistic)
} else {
ServiceOutcome sprints = sprintQueryService.getClosedSprints(user, (Query) rapidViewQuery.getValue())
if (!sprints.isValid()) {
return ServiceOutcomeImpl.error(sprints)
} else {

// Create a list of Mapped Status
Set<Status> mappedStatues = columnService.getMappedStatuses((RapidView) rapidView.getValue())

// Create a list of Mapped Status Ids from Mapped Statuses
ArrayList mappedStatusIds = new ArrayList()

for (Status status : mappedStatues) {
mappedStatusIds.add(status.getId())
}

List closedSprints = (List) sprints.getValue()
Collections.sort(closedSprints, new VelocityChartModelFactory.SprintComparator())
VelocityChartModel model = new VelocityChartModel()
int numSprints = closedSprints.size() > sprintCount.toInteger() ? sprintCount.toInteger() : closedSprints.size()
Iterator var10 = closedSprints.subList(0, numSprints).iterator()

while (var10.hasNext()) {
Sprint sprint = (Sprint) var10.next()
ServiceOutcome historyData = sprintBurndownModelFactory.getBurndownChangesForSprint(user, (RapidView) rapidView.getValue(), sprint)
if (!historyData.isValid()) {
return ServiceOutcomeImpl.error(historyData)
}

def valueResolver = statisticValueResolverFactory.forHistoricalEstimateStatisticValue((StatisticsField) estimateStatistic.getValue(), sprint, (Map) historyData.getValue(), mappedStatusIds)
model.sprints.add(sprintEntryFactory.newBaseTransformer(user).apply(sprint))
VelocityStatEntryFactory velocityStatEntryFactory = new VelocityStatEntryFactory(((Map) historyData.getValue()).keySet(), valueResolver)
model.velocityStatEntries.put(sprint.getId(), velocityStatEntryFactory.getVelocityStatEntry())
}

return ServiceOutcomeImpl.ok(model)
}
}
}

return Response.ok(new JsonBuilder().toString()).build()
}

Cheers!

DYelamos

Erik Saline Sep 28, 2017

That did the trick!! Thanks!!

 

I seem to get an exception during debugging but I do get the data I need. 

 

Thanks again!

 

 

Screen Shot 2017-09-28 at 4.19.46 PM.png

Sevak Asadorian Nov 16, 2017

Hi,

Trying to:

import com.onresolve.scriptrunner.runner.customisers.JiraAgileBean

 

What should get added to pom.xml? 

Sevak Asadorian Nov 16, 2017

nvm.

<dependency>
<groupId>com.onresolve.scriptrunner</groupId>
<artifactId>groovyrunner-5.2.1</artifactId>
<version>5.2.1</version>
<scope>system</scope>
<systemPath><path_to_jar>/groovyrunner-5.2.1.jar</systemPath>
</dependency>

Suggest an answer

Log in or Sign up to answer
This widget could not be displayed.
This widget could not be displayed.
Community showcase
Published in Next-gen

Introducing subtasks for breaking down work in next-gen projects

Teams break work down in order to help simplify complex tasks. This is often done iteratively, with tasks being broken down into smaller tasks and so on until the work is accurately captured in well-...

2,585 views 14 17
Read article

Community Events

Connect with like-minded Atlassian users at free events near you!

Find an event

Connect with like-minded Atlassian users at free events near you!

Unfortunately there are no Community Events near you at the moment.

Host an event

You're one step closer to meeting fellow Atlassian users at your local event. Learn more about Community Events

Events near you