Skip to end of metadata
Go to start of metadata

Cprime Apps has been rebranded as Anova Apps. Please note the only effect is the company name - all of our products’ names, logos, functionalities, support, etc. is exactly the same. The new location to our documentation space is

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:
 * Created at: 3/28/13, 3:02 PM  
 * File:
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 (
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;
    public SILType<MutableString> getType() {
        return TypeInst.STRING;

    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();

    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:
public void 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
                public FieldDescriptor createDescriptor(Issue issue, CustomField cf) {
                    return new ProjectCFDescriptor(projectManager);

public void doAtStop() {
    //first, make sure that super is called, even if it has an exception here
    try {
        //unregister the routine
        //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);

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

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

summary += " -- " + KProject; //where KProject is your CF name!
  • No labels