How to create a simple "customfield-searcher"?

Dear community,

I am struggeling with a custom-searcher.

I’ve created my own customfield-type and it works fine. I am able to create new custom fields based on my type and add them on my screens. Values get saved and everything is good. Now i need them to search. By JQL, by Java and things like that. I’ve learned, that I need to build/implement a customfield-searcher.

Following is status qou. It produces no errors, but work not as aspected:

Like I said, I’ve created my own customfield-type:

  <customfield-type key="de.mycompany.com.jira.customfields.qualitygate"
                    name="Quality Gate Picker"
                    i18n-name-key="Quality Gate Picker"
                    class="de.mycompany.com.jira.customfields.FieldQualityGate">

    <description>Choose the Quality Gate which the issue belongs to.</description>
    <resource name="view" type="velocity" location="/templates/fieldqualitygate/view.vm"/>
    <resource name="edit" type="velocity" location="/templates/fieldqualitygate/edit.vm"/>

  </customfield-type>

So far so good. Then, I added a customfield searcher:

  <customfield-searcher key="qualitygatesearcher" name="Quality Gate Searcher" class="de.mycompany.com.jira.searcher.QualityGateSearcher">
    <description>Allow searching for Quality Gates</description>
    <ressource type="velocity" name="search" location="/templates/fieldqualitygate/searcher_search.vm"/>
    <ressource type="velocity" name="view" location="/templates/fieldqualitygate/searcher_view.vm"/>
    <valid-customfield-type package="${atlassian.plugin.key}" key="de.mycompany.com.jira.customfields.qualitygate"/>
  </customfield-searcher>

My customfield-searcher class is the following:

package de.mycompany.com.jira.searcher;

import com.atlassian.jira.issue.customfields.searchers.TextSearcher;
import com.atlassian.jira.issue.customfields.searchers.transformer.CustomFieldInputHelper;
import com.atlassian.jira.jql.operand.JqlOperandResolver;
import com.atlassian.jira.web.FieldVisibilityManager;

public class QualityGateSearcher extends TextSearcher
{
    public QualityGateSearcher(FieldVisibilityManager fieldVisibilityManager, JqlOperandResolver jqlOperandResolver, CustomFieldInputHelper customFieldInputHelper)
    {
        super(fieldVisibilityManager, jqlOperandResolver, customFieldInputHelper);
    }

}

The result is: no errors but also no function. If I try to search by the custom field by JQL in JIRA itself, the custom field can not be found.

My JIRA Version is 7.13.1

Can you help me? Do you have any idea what I am doing wrong?

Kind regards
Manuel

2 Likes

Hi Steven. Do you probably have an idea what i am doing wrong @sfbehnke ? :grimacing: I have no clue why it is not working. Greetings!

This is just a simple guess but make sure you do have the Searcher assigned to your Custom Field. When you click “Edit” (I think that’s the option name) in the Issue->Custom Field list, for your Custom Field.

Do you expect to see JQL Functions? You would need to create a subclass of AbstractJqlFunction and add it to your atlassian-plugin XML.

1 Like

I haven’t toyed with searchers much. If I have the chance to look into it I’ll respond back.

Hello @m.miessner , I am having the same issue. Before you can search by JQL you have to choose the searcher for the field by editing it, then choosing the searcher.

In my case, there is no searcher listed from which to choose. I expect to see a text searcher.

In your case, did you ever solve this?
Could it be how you specify package="${atlassian.plugin.key}" ?
I used package="${project.groupId}.${project.artifactId}" but that didn’t work… still tryna figure it out.

Happy 2022!

Hello @splinterface ! Happy new year! Thank you for your response. Unfortunately, I didn’t solve the problem so it is still open. I can’t search my custom fields. My custom field itself works likes expected, but no search by JQL possible. :-/

It should be groupId and artifactId (You could test as static string, ex: de.mycompany.com.jira)

Do you guys maybe have errors in your logs when enabling your plugin? Everything looks properly configured from @m.miessner initial post (compared to our plugin).

Hello @linklefebvre, sorry for so late in replying…
I did find exceptions in the log:

2023-03-12 11:21:22,879-0400 http-nio-8080-exec-1 ERROR admin 681x29059x1 1cakmve 0:0:0:0:0:0:0:1 /secure/admin/EditCustomField!default.jspa [c.a.plugin.module.PrefixDelegatingModuleFactory] Detected an error instantiating the module via Spring. This usually means that you haven’t created a for the interface you’re trying to use. https://developer.atlassian.com/x/TAEr for more details.
2023-03-12 11:21:22,879-0400 http-nio-8080-exec-1 ERROR admin 681x29059x1 1cakmve 0:0:0:0:0:0:0:1 /secure/admin/EditCustomField!default.jspa [c.a.plugin.manager.SafeModuleExtractor] Exception when retrieving plugin module

org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name ‘com.atlassian.jira.issue.customfields.searchers.TextSearcher’: Unsatisfied dependency expressed through constructor parameter 0; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type ‘com.atlassian.jira.web.FieldVisibilityManager’ available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}
at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:800)
at org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:229)
at

In my case, I have example configuration like this – TRY to use Atlassian defaults:

<customfield-type key="myfield" name="testname" i18n-name-key="my.basic.label" class="com.example.fields.MyCustomField">
    <description key="my.description"></description>
    <resource type="velocity" name="view" location="/templates/mystuff/folder/basic/view.vm"/>
    <resource type="velocity" name="edit" location="/templates/mystuff/folder/basic/edit.vm"/>
    <resource type="velocity" name="xml" location="/templates/mystuff/folder/basic/xml.vm"/>
</customfield-type>


...


<customfield-searcher key="textsearcher" name="A Text Searcher"
                      i18n-name-key="admin.customfield.searcher.textsearcher.name"
                      class="com.atlassian.jira.issue.customfields.searchers.TextSearcher">
    <description key="admin.customfield.searcher.textsearcher.desc">blah blah.</description>

    <resource type="velocity" name="search" location="templates/plugins/fields/edit-searcher
       /search-basictext.vm"/>
    <resource type="velocity" name="view" location="templates/plugins/fields/view-searcher
       /view-searcher-basictext.vm"/>
    <valid-customfield-type package="com.example.fields" key="myfield"/>
</customfield-searcher>

But then, I got it working using the default searchers! To do so, I needed to add this to my custom field definition:

    <valid-searcher
            package="com.atlassian.jira.plugin.system.customfieldtypes"
            key="textsearcher"/>

and I also removed my “<customfield-searcher>”. Once I did that, I can now choose the searcher:

Thanks for the reply.

That is a sound solution when the goal is to index the custom field value as text and be able to search it with = or ~.

If you intend to support more complex advanced searching, creating your own searcher is required. Like looking for how many checklist items are checked, example: "checklist" > "50%".

@linklefebvre I know, this is an old post. And yet the only hint I found.

Can you elaborate on how to implement a custom field searcher like that?
Atlassian’s documentation is bad, to say the least.

What I am trying to do:
create a searcher with can do it all: Range (><), Exact (=), Text (~),

For example: “‘score’ = ‘3:4’” (exact score), “‘score’ ~ ‘3:4’” (approximation, might return 2:4, 3:3, 3:5, …), “‘score’ > 3” (any score where more than 3 wins occured) …

I am under the impression, that I need to do something like this:
a) implement a custom indexer for the different search scenarios
b) implement a custom field search which implements AbstractInitializationCustomFieldSearcher somehow to emulate NumberRangeSearcher, TextSearcher, …

My last resort is to download the Jira source code and look at how Atlassian did it in the searcher classes. Been trying to figure it our for days now. :pensive:

@DoItWithASmile

Indeed, in atlassian-plugin.xml you must have a <customfield-searcher> entry that uses a class extending AbstractInitializationCustomFieldSearcher

Here’s a simplified version of our Searcher:

public class CustomSearcher extends AbstractInitializationCustomFieldSearcher implements CustomFieldStattable {
    @Override
    public void init(CustomField field) {
        final ClauseNames names = field.getClauseNames();

        FieldIndexer indexer = new CustomIndexer(...);

        this.searcherInformation = new CustomFieldSearcherInformation(field.getId(), field.getNameKey(), Collections.<FieldIndexer>singletonList(indexer), new AtomicReference<CustomField>(field));
        this.searchRenderer = new CustomFieldRenderer(names, this.getDescriptor(), field, ...);
        this.searchInputTransformer = new CustomSearchInputTransformer(field, field.getId(), this.customFieldInputHelper, names, this.jqlOperandResolver);
        this.customFieldSearcherClauseHandler = new CustomSearcherClauseHandler(field, this.jqlOperandResolver);
    }

    @Override
    public CustomFieldSearcherClauseHandler getCustomFieldSearcherClauseHandler() {
        return this.customFieldSearcherClauseHandler;
    }

    @Override
    public SearcherInformation<CustomField> getSearchInformation() {
        return this.searcherInformation;
    }

    @Override
    public SearchInputTransformer getSearchInputTransformer() {
        return this.searchInputTransformer;
    }

    @Override
    public SearchRenderer getSearchRenderer() {
        return this.searchRenderer;
    }
}

I don’t know the best setup to achieve what you’re looking for. Here’s some pointers:

  • getSearchInformation must return a CustomFieldSearcherInformation using your custom field and your desired indexer. The indexer extends AbstractCustomFieldIndexer and decides what data gets indexed when your field is updated. Depending on your needs (storing your win/loss score system), you may want to create your own indexer or use something Jira already made.
  • getCustomFieldSearcherClauseHandler you can extend something like SimpleCustomFieldSearcherClauseHandler
    • You can override getSupportedOperators to make sure only = < > ~ are suppported.
    • You could override getClauseValidator to validate the search terms contains numbers or semicolons (3:4). (Return an error message to users if their search is not well formatted)
    • You can override getClauseQueryFactory to control how to search your field index. This is where you’ll code how to search your > "3" or = "3:4" in the index.

At the moment [changes are coming in Jira 11], the Jira DC indexing is all based on Apache Lucene. So you should get acquainted with how Lucene works. It’s designed to search words in a text document and we had to use clever workarounds to make it work for our field and use case.

Hope this helps!

1 Like