Are you in the loop? Keep up with the latest by making sure you're subscribed to Community Announcements. Just click Watch and select Articles.

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

Earn badges and make progress

You're on your way to the next level! Join the Kudos program to earn points and save your progress.

Deleted user Avatar
Deleted user

Level 1: Seed

25 / 150 points

Next: Root

Avatar

1 badge earned

Collect

Participate in fun challenges

Challenges come and go, but your rewards stay with you. Do more to earn more!

Challenges
Coins

Gift kudos to your peers

What goes around comes around! Share the love by gifting kudos to your peers.

Recognition
Ribbon

Rise up in the ranks

Keep earning points to reach the top of the leaderboard. It resets every quarter so you always have a chance!

Leaderboard

ScriptRunner script "Cannot find matching method" Transition

Hi! 

I'm sorry in advance if I sound like don't knw what I'm talking about. That's because I don't.

We've got 3 listener scripts set up, that copy issues from Service Desk to Core and sync all the info between the issues, including status, field updates and comments. At some point not long ago the script that synchronizes statuses stopped working.

We first thought that it cold be due to the fact that we've added some new events. We've updated the event list for the listener to include the new events. Apon investigating further we've discovered that there are two errors in the code: 

[Static type checking] - Cannot find matching method Transition#<init>(int,java.lang.Strng).

Here's the code

def transitionIssue(Issue issue, String value) {

if (value.equals(issue.getStatusId())) {
return;
}
WorkflowManager workflowManager = ComponentAccessor.getWorkflowManager();
IssueService issueService = ComponentAccessor.getIssueService()
// JiraAuthenticationContext jiraAuthenticationContext = ComponentAccessor.getJiraAuthenticationContext();
// ApplicationUser currentUser = jiraAuthenticationContext.getLoggedInUser();

try {

// jiraAuthenticationContext.setLoggedInUser(user);
String fromStatusId = issue.getStatus().getId();
//log.debug("Transitioning issue from " + issue.getStatus().getName() + "-" + fromStatusId + " to " + value);
JiraWorkflow workflow = workflowManager.getWorkflow(issue);
Map<String, Set<Transition>> transitionMap = new HashMap<>();
for (ActionDescriptor action : workflow.getAllActions()){
String statusToId = workflowManager.getNextStatusIdForAction(issue, action.getId());
//log.error("Action with id " +action.getId() + " leads to status " + statusToId);
if (!fromStatusId.equals(statusToId)) {
Transition transition = new Transition(action.getId(), statusToId);
for (StepDescriptor step: workflow.getStepsForTransition(action)){
transitionMap.compute((String) step.getMetaAttributes().get("jira.status.id"), new BiFunction<String, Set<Transition>, Set<Transition>>() {
@Override
public Set<Transition> apply(String k, Set<Transition> v) {
Set<Transition> transitionSet = v == null ? new HashSet<>() : v;
transitionSet.add(transition);
return transitionSet;
}
})
};
}
else {
log.error("The transition leads to itself");
}
};

 

and

[Static type checking] - Cannot call Script30#findPath(java.util.Map <java.lang.String,  java.util.Set>, java.util.Set < java.lang.String>, java.lang.String, java.lang.String) with arguments [java.util.Map<String, Set>, java.util.Set ,T extends java.lang.Object>, java.lan.String, java.land.String]

Code:

def Optional<List<Integer>> findPath(Map<String, Set<Transition>> transitionMap,
String statusFromId, String statusToId) {

return findPath(transitionMap, Collections.emptySet(), statusFromId, statusToId);
}

def Optional<List<Integer>> findPath(Map<String, Set<Transition>> transitionMap, Set<String> visited,
String statusFromId, String statusToId) {
List<Integer> shortestPath = null;
Set<Transition> transitions = transitionMap.get(statusFromId);
if (transitions == null) {
return Optional.empty();
} else {
Set<String> visitedPrime = new HashSet<>(visited);
visitedPrime.add(statusFromId);
for (Transition transition : transitions) {
if (transition.statusToId.equals(statusToId)) {
return Optional.of(Collections.singletonList(transition.actionId));
} else if (!visited.contains(transition.statusToId)) {
Optional<List<Integer>> path = findPath(transitionMap, visitedPrime, transition.statusToId, statusToId);
if (path.isPresent() && (shortestPath == null || shortestPath.size() - 1 > path.get().size())) {
shortestPath = new ArrayList<>();
shortestPath.add(transition.actionId);
shortestPath.addAll(path.get());
}
}
}
}
return Optional.ofNullable(shortestPath);
}

 Thank you in advance for any help! 

1 answer

Suggest an answer

Log in or Sign up to answer
1 vote
Benz Kek _Adaptavist_
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.
Jan 26, 2021

This looks more like a syntax error where it can't find the method you used which I suspect the culprit is this line: 

Transition transition = new Transition(action.getId(), statusToId);

 You are declaring the Transition with some invalid constructor. Not sure if this is your full code, but I don't see this variable was being used elsewhere. 

Thank you very much for the answer! My initial post did not contain the whole code, it's a rather long string. I'll post it here so that there is no confusion. What baffles me in this whole sitauation is that the listenere worked fine for three months and nobody made any changes in the code before the problem accured. 


@field Long linkTypeToProcess = 10400L;
@field ApplicationUser technicalUser = ComponentAccessor.getUserManager().getUserByName("admin");
@field MutableIssue issue = event.issue as MutableIssue;

ChangeHistoryManager historyManager = ComponentAccessor.getChangeHistoryManager();
def changeHistory = historyManager.getChangeHistoryById(event.getChangeLog().getLong("id"))
List<GenericValue> changeItems = changeHistory.getChangeItems()
//log.error(changeItems.toArray().toString())

for (GenericValue changeItem: changeItems){
def type = changeItem.getOrDefault("fieldtype","");
def field = changeItem.getOrDefault("field","");

if (type.equals("jira") && field.equals("status")){

IssueLinkManager linkManager = ComponentAccessor.getIssueLinkManager()

List<IssueLink> links = new ArrayList<>();
links.addAll(linkManager.getOutwardLinks(issue.getId()));
links.addAll(linkManager.getInwardLinks(issue.getId()));

for (IssueLink link : links){
if (!link.getLinkTypeId().equals(linkTypeToProcess)){
continue;
}
MutableIssue destinationIssue = (MutableIssue) link.getDestinationObject();
if (destinationIssue.getId().equals(issue.getId())){
destinationIssue = (MutableIssue) link.getSourceObject();
}

log.error("From " + issue.getKey())
log.error("To " + destinationIssue.getKey())

//log.error("Source status - " + issue.getStatus().getName() + " - " + issue.getStatus().getId())
//log.error("Target status - " + destinationIssue.getStatus().getName() + " - " + destinationIssue.getStatus().getId())

if (issue.getStatus().equals(destinationIssue.getStatus())){
continue;
}
try{
transitionIssue(destinationIssue, issue.getStatus().getId())
}
catch (Exception e){
log.error(e.getMessage())
}
}
}
}

def transitionIssue(Issue issue, String value) {

if (value.equals(issue.getStatusId())) {
return;
}
WorkflowManager workflowManager = ComponentAccessor.getWorkflowManager();
IssueService issueService = ComponentAccessor.getIssueService()
// JiraAuthenticationContext jiraAuthenticationContext = ComponentAccessor.getJiraAuthenticationContext();
// ApplicationUser currentUser = jiraAuthenticationContext.getLoggedInUser();

try {

// jiraAuthenticationContext.setLoggedInUser(user);
String fromStatusId = issue.getStatus().getId();
//log.debug("Transitioning issue from " + issue.getStatus().getName() + "-" + fromStatusId + " to " + value);
JiraWorkflow workflow = workflowManager.getWorkflow(issue);
Map<String, Set<Transition>> transitionMap = new HashMap<>();
for (ActionDescriptor action : workflow.getAllActions()){
String statusToId = workflowManager.getNextStatusIdForAction(issue, action.getId());
//log.error("Action with id " +action.getId() + " leads to status " + statusToId);
if (!fromStatusId.equals(statusToId)) {
Transition transition = new Transition(action.getId(), statusToId);
for (StepDescriptor step: workflow.getStepsForTransition(action)){
transitionMap.compute((String) step.getMetaAttributes().get("jira.status.id"), new BiFunction<String, Set<Transition>, Set<Transition>>() {
@Override
public Set<Transition> apply(String k, Set<Transition> v) {
Set<Transition> transitionSet = v == null ? new HashSet<>() : v;
transitionSet.add(transition);
return transitionSet;
}
})
};
}
else {
log.error("The transition leads to itself");
}
};

Optional<List<Integer>> path = findPath(transitionMap, issue.getStatusId(), value);
if (path.isPresent()) {
for (int actionId : path.get()) {
//log.error("Performing action " + actionId);
IssueService.TransitionValidationResult transitionValidationResult = issueService.validateTransition(
technicalUser, issue.getId(), actionId, issueService.newIssueInputParameters()
);
if (transitionValidationResult.isValid()) {
issueService.transition(technicalUser, transitionValidationResult);
} else {
log.error("Error transitioning issue: " + transitionValidationResult.getErrorCollection());
break;
}
}
} else {
log.error("Could not find transition sequence from status " + issue.getStatusId() + " to " + value);
}
} catch (Exception e) {
log.error(e.getMessage());
}
// finally {
// jiraAuthenticationContext.setLoggedInUser(currentUser);
// }


}

def Optional<List<Integer>> findPath(Map<String, Set<Transition>> transitionMap,
String statusFromId, String statusToId) {

return findPath(transitionMap, Collections.emptySet(), statusFromId, statusToId);
}

def Optional<List<Integer>> findPath(Map<String, Set<Transition>> transitionMap, Set<String> visited,
String statusFromId, String statusToId) {
List<Integer> shortestPath = null;
Set<Transition> transitions = transitionMap.get(statusFromId);
if (transitions == null) {
return Optional.empty();
} else {
Set<String> visitedPrime = new HashSet<>(visited);
visitedPrime.add(statusFromId);
for (Transition transition : transitions) {
if (transition.statusToId.equals(statusToId)) {
return Optional.of(Collections.singletonList(transition.actionId));
} else if (!visited.contains(transition.statusToId)) {
Optional<List<Integer>> path = findPath(transitionMap, visitedPrime, transition.statusToId, statusToId);
if (path.isPresent() && (shortestPath == null || shortestPath.size() - 1 > path.get().size())) {
shortestPath = new ArrayList<>();
shortestPath.add(transition.actionId);
shortestPath.addAll(path.get());
}
}
}
}
return Optional.ofNullable(shortestPath);
}

class Transition {
private final int actionId;
private final String statusToId;

private Transition(int actionId, String statusToId) {
this.actionId = actionId;
this.statusToId = statusToId;
}

@Override
public boolean equals(Object o) {
if (o == null || getClass() != o.getClass()) return false;
Transition that = (Transition) o;
return Objects.equals(statusToId, that.statusToId);
}

@Override
public int hashCode() {
return Objects.hash(statusToId);
}
}
Benz Kek _Adaptavist_
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.
Jan 30, 2021

Your Transition class constructor has been set to private, causing it to not accessible. 

private Transition(int actionId, String statusToId) {
this.actionId = actionId;
this.statusToId = statusToId;
}

Please remove the private and try again. 

Like Jevgenija K likes this

Thank you very much for your help! This solved one error, but the other one persists and the listener still does not sync the issue statuses, unfortunetly. 

This is the error:

[Static type checking] - Cannot call Script30#findPath(java.util.Map <java.lang.String,  java.util.Set>, java.util.Set < java.lang.String>, java.lang.String, java.lang.String) with arguments [java.util.Map<String, Set>, java.util.Set ,T extends java.lang.Object>, java.lan.String, java.lang.String]

and this is the line of code, where the error pops (line 134, column 16): 

return findPath(transitionMap, Collections.emptySet(), statusFromId, statusToId);
TAGS
AUG Leaders

Atlassian Community Events