Step 3: Creating a Custom Field Descriptor

Looking for the documentation on the newest versions of SIL Engine and the Simple Issue Language for Jira 8 for Server/Data Center? Click here !

Project Picker CF

Let's say you need to provide support for a certain custom field. Power Scripts™ for Jira does offer support for the project picker CF but for educational purposes, let's see how you could add the support if it didn't.


The task is to register a translator from SILValue to the native object type and the other way around.

The code is presented below:

ProjectCFDescriptor.java
/*
 * Created at: 3/28/13, 3:02 PM  
 * 
 * File: ProjectCFDescriptor.java
 */
package com.mycompany.silexample;

import com.atlassian.jira.project.Project;
import com.atlassian.jira.project.ProjectManager;
import com.keplerrominfo.sil.lang.*;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.ofbiz.core.entity.GenericValue;

import com.keplerrominfo.common.util.MutableString;
import com.keplerrominfo.common.util.StringUtils;
import com.keplerrominfo.jira.commons.ivm.FieldDescriptor;
import com.keplerrominfo.sil.lang.type.TypeInst;

/**
 * The project CF descriptor, com.atlassian.jira.plugin.system.customfieldtypes:project
 *
 * @author Radu Dumitriu (rdumitriu@gmail.com)
 */
public class ProjectCFDescriptor implements FieldDescriptor<GenericValue, MutableString> {
    //This template class tells us that the values exchanged are GenericValue (JIRA side) and MutableString (SIL)

    private static final Log LOG = LogFactory.getLog(ProjectCFDescriptor.class);
    
    private final ProjectManager projectManager;
    
    
    public ProjectCFDescriptor(ProjectManager projectManager) {
        this.projectManager = projectManager;
    }
    
    @Override
    public SILType<MutableString> getType() {
        return TypeInst.STRING;
    }


    @Override
    public GenericValue toJiraValue(SILContext ctx, SILValue<MutableString> value) {
        String projectKey = StringUtils.trim(value.toStringValue());
        if (projectKey == null) {
            return null;
        }
        Project project = projectManager.getProjectObjByKey(projectKey);
        if(project == null) {
            LOG.warn(String.format(">>%s<< is not a valid project key", projectKey));
            return null;
        }
        // Project picker CF stores the value as GenericValue. This is deprecated, but we need to call it
        return project.getGenericValue();
    }

    @Override
    public SILValue<MutableString> toSILValue(SILContext ctx, GenericValue value) {
        return value != null ? SILValueFactory.string(value.getString("key")) : SILValueFactory.string();
    }
}


Register a CF descriptor in the launcher:

BundleActivator.java
@Override
public void doAtLaunch() {
    super.doAtLaunch();

    //register the routine
    RoutineRegistry.register(new ReverseStringRoutine("myReverseString"));

    //register the CF descriptor
    customFieldDescriptorRegistry.register("com.atlassian.jira.plugin.system.customfieldtypes:project", //this is the real key of the CF
            new AbstractCustomFieldDescriptorFactory(
                    "example.project.cfdf", //internal identification. Must be unique in the SIL system
                    "Project Key to String", //short description, followed by a longer one
                    "Extract the project key using GenericValue or project") {

				// Descriptors are created when needed, and some of them might be contextual. This is why you register here a creator of a
			    // descriptor and not the real descriptor
			    @Override
                public FieldDescriptor createDescriptor(Issue issue, CustomField cf) {
                    return new ProjectCFDescriptor(projectManager);
                }
            }
    );
}

@Override
public void doAtStop() {
    //first, make sure that super is called, even if it has an exception here
    try {
        //unregister the routine
        RoutineRegistry.unregister("myReverseString");
        
        //unregister the CF descriptor
        customFieldDescriptorRegistry.unregister("com.atlassian.jira.plugin.system.customfieldtypes:project");  //this is the real key of the CF
    } catch(Exception e) {
        LOG.error("Failed to unregister!", e);
    }
    
    super.doAtStop();
}


Line 9 registers the CF into our CF translators map. Hooray!


That's all you need. You can now play with SIL™ like such:

something.sil
summary += " -- " + KProject; //where KProject is your CF name!