How can I override DateCompare jql function? Or, how can I validate that first parameter of this function must not be empty?

Vladimir Alehin November 30, 2016

Hi,

we have a lot of issues in our JIRA, so we have a problems with DateCompare jql function when user use an empty first parameter.. How can I override or extend DateCompare jql function? Or, how can I validate that first parameter of this function must not be empty? ScriptRunner 3.0.16

1 answer

0 votes
Thanos Batagiannis _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.
December 1, 2016

Hi Vladimir,

There is a relevant section in the Script Runner documentation - Custom JQL Functions, please let me know if you need further assistance. 

regards, Thanos

Vladimir Alehin December 1, 2016

Hi Thanos,

I took as a basis the function DateCompare.groovy, and add my validation method MessageSet nonEmptyValidate(String s), so, result:

package com.onresolve.jira.groovy.jql

import com.atlassian.core.util.DateUtils
import com.atlassian.core.util.InvalidDurationException
import com.atlassian.crowd.embedded.api.User
import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.datetime.LocalDate
import com.atlassian.jira.issue.DocumentIssueImpl
import com.atlassian.jira.issue.customfields.impl.DateCFType
import com.atlassian.jira.issue.customfields.impl.DateTimeCFType
import com.atlassian.jira.issue.fields.CustomField
import com.atlassian.jira.issue.index.DocumentConstants
import com.atlassian.jira.issue.search.filters.IssueIdFilter
import com.atlassian.jira.jql.query.QueryCreationContext
import com.atlassian.jira.jql.util.JqlLocalDateSupport
import com.atlassian.jira.jql.validator.NumberOfArgumentsValidator
import com.atlassian.jira.util.LuceneUtils
import com.atlassian.jira.util.MessageSet
import com.atlassian.jira.util.MessageSetImpl
import com.atlassian.query.clause.TerminalClause
import com.atlassian.query.operand.FunctionOperand
import org.apache.log4j.Category
import org.apache.lucene.index.Term
import org.apache.lucene.search.*
import java.sql.Timestamp

class StcDateCompare extends AbstractScriptedJqlFunction implements JqlQueryFunction{
    private def String subquery
    private def log = Category.getInstance(StcDateCompare.class)
    static def GREATER_THAN = ">"
    static def LESS_THAN = "<"
    private def List dateParams
    private def op, lhs, rhs
    private def String leftField, rightField
    def customFieldManager = ComponentAccessor.getCustomFieldManager()
    def jqlLocalDateSupport = ComponentAccessor.getComponent(JqlLocalDateSupport.class)
    private def Map<String,CustomField> cfMap = [:]

    @Override
    MessageSet validate(User user, FunctionOperand operand, TerminalClause terminalClause) {
        def messageSet = new NumberOfArgumentsValidator(2, 2, getI18n()).validate(operand)
        subquery = operand.args[0]
        def dateStr = operand.args[1]
        messageSet.addMessageSet validateDateComparison(dateStr)
	messageSet.addMessageSet nonEmptyValidate(subquery)
        if (messageSet.hasAnyErrors()) {
            messageSet.addErrorMessage("Use a comparison like: \"dueDate > resolutionDate\", or \"dueDate > resolutionDate + 2w\"," +
                " or \"My Date Custom Field > My Other Date Custom Field\"")
            return messageSet
        }
        // dateParams = dateCompareParser(dateStr)
        (op, lhs, rhs) = dateParams
        leftField = lhs[0]
        rightField = rhs[0]
        if (subquery) {
            messageSet.addMessageSet (validateSubquery(user, subquery))
        }
        messageSet
    }

    @Override
    String getDescription() {
        "Compare dates"
    }

    @Override
    List<Map> getArguments() {
        [
            ["description": "subquery", "optional": false],
            ["description": "comparison", "optional": false]
        ]
    }

    @Override
    String getFunctionName() {
        "altDateCompare"
    }

    MessageSet validateDateComparison(String dateString) {
        def messageSet = new MessageSetImpl()
    try {
            dateParams = dateCompareParser(dateString)
        } catch (Exception e) {
            messageSet.addErrorMessage(e.message)
        }
        messageSet
    }

    MessageSet nonEmptyValidate(String s){
	def messageSet = new MessageSetImpl()
	if(s == null || s.equals("") || s == ""){
	    messageSet.addErrorMessage("KOSYAK")
	}
	messageSet
    }	

    Calendar getFieldCalendar(DocumentIssueImpl issue, String field, Long adjustment) {
        def cal = Calendar.getInstance()
        def timestamp
        if (field.startsWith("customfield_")) {
            if (! cfMap.containsKey(field)) {
                cfMap.put(field, customFieldManager.getCustomFieldObject(field))
            }
            timestamp = issue.getCustomFieldValue(cfMap.get(field)) as Timestamp
        }
        else if (isIndexOnlyField(field)) {
            def document = issue.document
            LocalDate localDate = (LocalDate) LuceneUtils.stringToLocalDate(document.get(field))
            timestamp = new Timestamp(jqlLocalDateSupport.convertToDate(localDate).getTime());
        }
       // need to disambiguated getCreated from isCreated
        else if (field == "created") {
            timestamp = issue.getCreated()
        }
        else {
            timestamp = issue[field as String] as Timestamp
        }
        // log.debug("timestamp (${field}): " + timestamp
        cal.setTime(new Date(timestamp.getTime()))
        cal.add(Calendar.SECOND, adjustment as Integer)
        cal
    }

    Query getQuery(QueryCreationContext queryCreationContext, FunctionOperand operand, TerminalClause terminalClause) {
        validate(queryCreationContext.user, operand, terminalClause)
        Set issueIds = new HashSet()
        def nonEmpyQuery = new BooleanQuery()
        nonEmpyQuery.add(new TermQuery(new Term(DocumentConstants.ISSUE_NON_EMPTY_FIELD_IDS, leftField.toLowerCase())), BooleanClause.Occur.MUST)
        nonEmpyQuery.add(new TermQuery(new Term(DocumentConstants.ISSUE_NON_EMPTY_FIELD_IDS, rightField.toLowerCase())), BooleanClause.Occur.MUST)
        //log.debug("nonEmpyQuery: ${nonEmpyQuery}")
        def filterCollector = [apply: {DocumentIssueImpl issue ->
//            if (! (issue[leftField] && issue[rightField])) {
//                return
//            }
            def lhsCal = getFieldCalendar(issue, leftField, lhs[1] as Long)
            def rhsCal = getFieldCalendar(issue, rightField, rhs[1] as Long)
            def match
//            log.debug("dates")
//            log.debug("lhs dae: field: ${lhs[0]}, adjustment ${lhs[1]}: " + lhsCal.getTime())
//            log.debug("rhs date: field: ${rhs[0]}, adjustment ${rhs[1]}: " + rhsCal.getTime())
//            log.debug("Comparison: ${lhs[0]} " + (lhsCal.compareTo(rhsCal) < 0 ? "BEFORE" : "AFTER") + " ${rhs[0]}")
            if (op == LESS_THAN) {
                match = lhsCal.compareTo(rhsCal) < 1
            }
            else {
                match = (lhsCal.compareTo(rhsCal) > 0)
            }
            if (match) {
                issueIds << (issue.id as String)
            }
        }] as FilterCollector
        getIssues(subquery, queryCreationContext.applicationUser, nonEmpyQuery, filterCollector as FilterCollector)
        new ConstantScoreQuery(new IssueIdFilter(issueIds))
    }

    // todo: maybe shd be static
    public List dateWindowParser(String param) throws InvalidDurationException {
        param = param.trim()
        // if we don't have +- then just returned the trimmed field na
        if (! (param =~ /[+-]/)) {
            return [resolveField(param), 0]
        }
        // todo: add custom fields
        // else split on +- and trim
        def m = param =~ /(.*)([+-])(.*)/
        def (String fieldname, String op, String timeInterval) = m[0][1..3].collect {it.toString().trim()}
        // log.debug("$fieldname, $op, $timeInterval")
        fieldname = resolveField(fieldname)
        def Long duration
        try {
            duration = DateUtils.getDuration(timeInterval as String)
        } catch (InvalidDurationException e) {
            throw new InvalidDurationException("${timeInterval}: ${e.message}.")
        }
        if (op == "-") {
            duration = duration.unaryMinus()
        }
        [fieldname, duration]
    }

    public static isIndexOnlyField(String fieldname) {
        return ["sr_first_cmmt_dt", "sr_last_cmmt_dt"].contains(fieldname)
    }

    /**
     * Resolve a fieldname like duedate to dueDate, suitable for looking up in the index
     * @return name of field as found in the index
     * @throws Exception field name not supported
     */

    public String resolveField(String fieldname) throws Exception {
        // validate acceptable fields. Map lowercase to case of the property
        def dateSystemFields = [
            created:            "created",
            updated:            "updated",
            resolutiondate:     "resolutionDate",
            resolved:           "resolutionDate",
            duedate:            "dueDate",
            firstcommented:     "sr_first_cmmt_dt",
            lastcommented:      "sr_last_cmmt_dt",
        ]

        if (dateSystemFields.containsKey(fieldname.toLowerCase())) {
            return dateSystemFields.get(fieldname.toLowerCase())
        }
        // check custom fields by name
        def fields = customFieldManager.getCustomFieldObjectsByName(fieldname)
        def dateTimeCf = fields.find {
            it.customFieldType instanceof DateCFType || it.customFieldType instanceof DateTimeCFType
        }
        if (! dateTimeCf) {
            throw new Exception ("Field name: ${fieldname} not found or not a date or datetime.")
        }
        else {
            return dateTimeCf.id
        }
    }

    public List dateCompareParser(String param) {
        if (! (param =~ /[<>]/)) {
            throw new Exception("The comparison must contain a either > or < .")
        }
        def m = param =~ /(.*)([<>])(.*)/
        def (lhs, op, rhs) = m[0][1..3].collect {it.toString().trim()}
        // parse each side separately
        // support duedate, created, lastcommented, resolutionDate and date custom fields
        [op, dateWindowParser(lhs), dateWindowParser(rhs)]
    }
}

I put my function to /var/atlassian/application-data/jira/scripts/com/onresolve/jira/groovy/jql/.

So, validation works, but when I pass a valid JQL to the first parameter, I get an exception:

No signature of method: com.onresolve.jira.groovy.jql.StcDateCompare.getIssues() is applicable for argument types: (java.lang.String, com.atlassian.jira.user.DelegatingApplicationUser, org.apache.lucene.search.BooleanQuery, com.sun.proxy.$Proxy3467) values: [project = SmartLoggerII and type = Reclamation, alekhin(alekhin), ...]
Possible solutions: getIssues(), getIssues(java.lang.String, com.atlassian.jira.user.ApplicationUser), getIssues(java.lang.String, com.atlassian.jira.user.ApplicationUser, org.apache.lucene.search.Query), getIssues(java.lang.String, com.atlassian.jira.user.ApplicationUser, org.apache.lucene.search.Query, com.onresolve.jira.groovy.jql.FilterCollector), setIssues(java.util.List)
groovy.lang.MissingMethodException: No signature of method: com.onresolve.jira.groovy.jql.StcDateCompare.getIssues() is applicable for argument types: (java.lang.String, com.atlassian.jira.user.DelegatingApplicationUser, org.apache.lucene.search.BooleanQuery, com.sun.proxy.$Proxy3467) values: [project = SmartLoggerII and type = Reclamation, alekhin(alekhin), ...]
Possible solutions: getIssues(), getIssues(java.lang.String, com.atlassian.jira.user.ApplicationUser), getIssues(java.lang.String, com.atlassian.jira.user.ApplicationUser, org.apache.lucene.search.Query), getIssues(java.lang.String, com.atlassian.jira.user.ApplicationUser, org.apache.lucene.search.Query, com.onresolve.jira.groovy.jql.FilterCollector), setIssues(java.util.List)
	at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.unwrap(ScriptBytecodeAdapter.java:56)
	at org.codehaus.groovy.runtime.callsite.PogoMetaClassSite.callCurrent(PogoMetaClassSite.java:78)
	at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCallCurrent(CallSiteArray.java:49)
	at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:151)
	at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:187)
	at com.onresolve.jira.groovy.jql.StcDateCompare.getQuery(StcDateCompare.groovy:174)
	at com.onresolve.jira.groovy.jql.JqlQueryFunction$getQuery.call(Unknown Source)
	at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:45)
	at com.onresolve.jira.groovy.jql.DateCompare$getQuery$1.call(Unknown Source)
	at com.onresolve.jira.groovy.jql.ScriptedJqlFunction.getQuery(ScriptedJqlFunction.groovy:99)
	at com.onresolve.jira.groovy.jql.ScriptedJqlFunction$getQuery.call(Unknown Source)
	at com.onresolve.jira.groovy.jql.ScriptedFunctionClauseFactory.getQuery(ScriptedFunctionClauseFactory.groovy:57)
	at com.atlassian.jira.jql.query.QueryVisitor.visit(QueryVisitor.java:155)
	at com.atlassian.jira.jql.query.QueryVisitor.visit(QueryVisitor.java:25)
	at com.atlassian.query.clause.TerminalClauseImpl.accept(TerminalClauseImpl.java:162)
	at com.atlassian.jira.jql.query.QueryVisitor.createQuery(QueryVisitor.java:72)
	at com.atlassian.jira.jql.query.DefaultLuceneQueryBuilder.createLuceneQuery(DefaultLuceneQueryBuilder.java:39)
	at com.atlassian.jira.issue.search.providers.LuceneSearchProvider.createLuceneQuery(LuceneSearchProvider.java:364)
	at com.atlassian.jira.issue.search.providers.LuceneSearchProvider.getHits(LuceneSearchProvider.java:284)
	at com.atlassian.jira.issue.search.providers.LuceneSearchProvider.searchAndSort(LuceneSearchProvider.java:464)
	at com.atlassian.jira.issue.search.providers.LuceneSearchProvider.searchAndSort(LuceneSearchProvider.java:179)  <+2> (DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:606)
	at com.atlassian.plugin.osgi.hostcomponents.impl.DefaultComponentRegistrar$ContextClassLoaderSettingInvocationHandler.invoke(DefaultComponentRegistrar.java:129)
	at com.sun.proxy.$Proxy73.searchAndSort(Unknown Source)  <+2> (DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:606)
	at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:307)
	at org.springframework.osgi.service.importer.support.internal.aop.ServiceInvoker.doInvoke(ServiceInvoker.java:58)
	at org.springframework.osgi.service.importer.support.internal.aop.ServiceInvoker.invoke(ServiceInvoker.java:62)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:171)
	at org.springframework.aop.support.DelegatingIntroductionInterceptor.doProceed(DelegatingIntroductionInterceptor.java:131)
	at org.springframework.aop.support.DelegatingIntroductionInterceptor.invoke(DelegatingIntroductionInterceptor.java:119)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:171)
	at org.springframework.osgi.service.util.internal.aop.ServiceTCCLInterceptor.invokeUnprivileged(ServiceTCCLInterceptor.java:56)
	at org.springframework.osgi.service.util.internal.aop.ServiceTCCLInterceptor.invoke(ServiceTCCLInterceptor.java:39)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:171)
	at org.springframework.osgi.service.importer.support.LocalBundleContextAdvice.invoke(LocalBundleContextAdvice.java:59)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:171)
	at org.springframework.aop.support.DelegatingIntroductionInterceptor.doProceed(DelegatingIntroductionInterceptor.java:131)
	at org.springframework.aop.support.DelegatingIntroductionInterceptor.invoke(DelegatingIntroductionInterceptor.java:119)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:171)
	at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:204)
	at com.sun.proxy.$Proxy2538.searchAndSort(Unknown Source)
	at com.atlassian.jira.plugin.issuenav.service.issuetable.AbstractIssueTableCreator.collectIssues(AbstractIssueTableCreator.java:166)
	at com.atlassian.jira.plugin.issuenav.service.issuetable.AbstractIssueTableCreator.executeNormalSearch(AbstractIssueTableCreator.java:236)
	at com.atlassian.jira.plugin.issuenav.service.issuetable.AbstractIssueTableCreator.create(AbstractIssueTableCreator.java:202)
	at com.atlassian.jira.plugin.issuenav.service.issuetable.DefaultIssueTableService.createIssueTableFromCreator(DefaultIssueTableService.java:188)
	at com.atlassian.jira.plugin.issuenav.service.issuetable.DefaultIssueTableService.getIssueTable(DefaultIssueTableService.java:302)
	at com.atlassian.jira.plugin.issuenav.service.issuetable.DefaultIssueTableService.getIssueTableFromFilterWithJql(DefaultIssueTableService.java:124)
	at com.atlassian.jira.plugin.issuenav.rest.IssueTableResource.getIssueTableHtml(IssueTableResource.java:99)  <+3> (NativeMethodAccessorImpl.java:57) (DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:606)
	at com.sun.jersey.spi.container.JavaMethodInvokerFactory$1.invoke(JavaMethodInvokerFactory.java:60)  <+12> (AbstractResourceMethodDispatchProvider.java:205) (ResourceJavaMethodDispatcher.java:75) (HttpMethodRule.java:288) (ResourceClassRule.java:108) (RightHandPathRule.java:147) (RootResourceClassesRule.java:84) (WebApplicationImpl.java:1469) (WebApplicationImpl.java:1400) (WebApplicationImpl.java:1349) (WebApplicationImpl.java:1339) (WebComponent.java:416) (ServletContainer.java:537)
	at com.atlassian.plugins.rest.module.RestDelegatingServletFilter$JerseyOsgiServletContainer.doFilter(RestDelegatingServletFilter.java:178)  <+1> (ServletContainer.java:795)
	at com.atlassian.plugins.rest.module.RestDelegatingServletFilter.doFilter(RestDelegatingServletFilter.java:73)  <+16> (DelegatingPluginFilter.java:74) (IteratingFilterChain.java:42) (ServletFilterModuleContainerFilter.java:77) (ServletFilterModuleContainerFilter.java:63) (DelegatingPluginFilter.java:74) (IteratingFilterChain.java:42) (DelegatingPluginFilter.java:66) (RestServletUtilsUpdaterFilter.java:26) (RestServletUtilsUpdaterFilter.java:40) (DelegatingPluginFilter.java:74) (IteratingFilterChain.java:42) (DelegatingPluginFilter.java:66) (ContextFilter.java:25) (DelegatingPluginFilter.java:74) (IteratingFilterChain.java:42) (DelegatingPluginFilter.java:66)
	at com.atlassian.mywork.client.filter.ServingRequestsFilter.doFilter(ServingRequestsFilter.java:37)  <+3> (DelegatingPluginFilter.java:74) (IteratingFilterChain.java:42) (DelegatingPluginFilter.java:66)
	at com.atlassian.plugins.cors.CorsFilter.doFilter(CorsFilter.java:65)  <+3> (DelegatingPluginFilter.java:74) (IteratingFilterChain.java:42) (DelegatingPluginFilter.java:66)
	at com.atlassian.prettyurls.filter.PrettyUrlsDispatcherFilter.doFilter(PrettyUrlsDispatcherFilter.java:60)  <+3> (DelegatingPluginFilter.java:74) (IteratingFilterChain.java:42) (DelegatingPluginFilter.java:66)
	at com.atlassian.prettyurls.filter.PrettyUrlsSiteMeshFilter.doFilter(PrettyUrlsSiteMeshFilter.java:92)  <+3> (DelegatingPluginFilter.java:74) (IteratingFilterChain.java:42) (DelegatingPluginFilter.java:66)
	at com.atlassian.prettyurls.filter.PrettyUrlsMatcherFilter.doFilter(PrettyUrlsMatcherFilter.java:56)  <+3> (DelegatingPluginFilter.java:74) (IteratingFilterChain.java:42) (DelegatingPluginFilter.java:66)
	at com.atlassian.labs.botkiller.BotKillerFilter.doFilter(BotKillerFilter.java:36)  <+18> (DelegatingPluginFilter.java:74) (IteratingFilterChain.java:42) (ServletFilterModuleContainerFilter.java:77) (ServletFilterModuleContainerFilter.java:63) (ApplicationFilterChain.java:243) (ApplicationFilterChain.java:210) (AccessLogFilter.java:103) (AccessLogFilter.java:87) (ApplicationFilterChain.java:243) (ApplicationFilterChain.java:210) (XsrfTokenAdditionRequestFilter.java:54) (ApplicationFilterChain.java:243) (ApplicationFilterChain.java:210) (ChainedFilterStepRunner.java:87) (ApplicationFilterChain.java:243) (ApplicationFilterChain.java:210) (IteratingFilterChain.java:46) (DelegatingPluginFilter.java:66)
	at com.atlassian.prettyurls.filter.PrettyUrlsCombinedMatchDispatcherFilter.doFilter(PrettyUrlsCombinedMatchDispatcherFilter.java:61)  <+22> (DelegatingPluginFilter.java:74) (IteratingFilterChain.java:42) (ServletFilterModuleContainerFilter.java:77) (ServletFilterModuleContainerFilter.java:63) (ApplicationFilterChain.java:243) (ApplicationFilterChain.java:210) (SecurityFilter.java:234) (ApplicationFilterChain.java:243) (ApplicationFilterChain.java:210) (TrustedApplicationsFilter.java:100) (ApplicationFilterChain.java:243) (ApplicationFilterChain.java:210) (BaseLoginFilter.java:169) (JiraLoginFilter.java:70) (ApplicationFilterChain.java:243) (ApplicationFilterChain.java:210) (IteratingFilterChain.java:46) (DelegatingPluginFilter.java:66) (OAuthFilter.java:61) (DelegatingPluginFilter.java:74) (IteratingFilterChain.java:42) (DelegatingPluginFilter.java:66)
	at com.atlassian.plugins.rest.module.servlet.RestSeraphFilter.doFilter(RestSeraphFilter.java:40)  <+3> (DelegatingPluginFilter.java:74) (IteratingFilterChain.java:42) (DelegatingPluginFilter.java:66)
	at com.atlassian.prettyurls.filter.PrettyUrlsCombinedMatchDispatcherFilter.doFilter(PrettyUrlsCombinedMatchDispatcherFilter.java:61)  <+9> (DelegatingPluginFilter.java:74) (IteratingFilterChain.java:42) (ServletFilterModuleContainerFilter.java:77) (ServletFilterModuleContainerFilter.java:63) (ApplicationFilterChain.java:243) (ApplicationFilterChain.java:210) (AbstractJohnsonFilter.java:71) (ApplicationFilterChain.java:243) (ApplicationFilterChain.java:210)
	at org.tuckey.web.filters.urlrewrite.RuleChain.handleRewrite(RuleChain.java:176)
	at org.tuckey.web.filters.urlrewrite.RuleChain.doRules(RuleChain.java:145)
	at org.tuckey.web.filters.urlrewrite.UrlRewriter.processRequest(UrlRewriter.java:92)  <+10> (UrlRewriteFilter.java:394) (ApplicationFilterChain.java:243) (ApplicationFilterChain.java:210) (GzipFilter.java:74) (GzipFilter.java:51) (JiraGzipFilter.java:55) (ApplicationFilterChain.java:243) (ApplicationFilterChain.java:210) (IteratingFilterChain.java:46) (DelegatingPluginFilter.java:66)
	at com.atlassian.prettyurls.filter.PrettyUrlsCombinedMatchDispatcherFilter.doFilter(PrettyUrlsCombinedMatchDispatcherFilter.java:61)  <+40> (DelegatingPluginFilter.java:74) (IteratingFilterChain.java:42) (ServletFilterModuleContainerFilter.java:77) (ServletFilterModuleContainerFilter.java:63) (ApplicationFilterChain.java:243) (ApplicationFilterChain.java:210) (ChainedFilterStepRunner.java:87) (ApplicationFilterChain.java:243) (ApplicationFilterChain.java:210) (AbstractCachingFilter.java:33) (AbstractHttpFilter.java:31) (ApplicationFilterChain.java:243) (ApplicationFilterChain.java:210) (AbstractEncodingFilter.java:41) (AbstractHttpFilter.java:31) (PathMatchingEncodingFilter.java:45) (AbstractHttpFilter.java:31) (ApplicationFilterChain.java:243) (ApplicationFilterChain.java:210) (JiraStartupChecklistFilter.java:78) (ApplicationFilterChain.java:243) (ApplicationFilterChain.java:210) (MultipartBoundaryCheckFilter.java:41) (ApplicationFilterChain.java:243) (ApplicationFilterChain.java:210) (ChainedFilterStepRunner.java:87) (JiraFirstFilter.java:57) (ApplicationFilterChain.java:243) (ApplicationFilterChain.java:210) (StandardWrapperValve.java:222) (StandardContextValve.java:123) (AuthenticatorBase.java:502) (StandardHostValve.java:171) (ErrorReportValve.java:100) (StandardEngineValve.java:118) (AccessLogValve.java:953) (CoyoteAdapter.java:408) (AbstractHttp11Processor.java:1041) (AbstractProtocol.java:603) (JIoEndpoint.java:310)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
	at java.lang.Thread.run(Thread.java:745)

Exception indicates that there is no method getIssues(...), which would correspond to the fact that we are passing it. I tried to override getIssues(...) method, cast parameters on it and try to call super.getIssues(...), but in this way I get exception, that super-class and child class has different classloaders..

Did I do something wrong?

I also tried to add validation in to DateCompare.groovy, pack it into .JAR and install to JIRA, but this way validation is not work. As if I did not change anything.. why?

 

I'll be very grateful if you can help. Regards, Vladimir.

Vladimir Alehin December 4, 2016

@Thanos Batagiannis [Adaptavist], I need your help!

Suggest an answer

Log in or Sign up to answer