Hi everyone,

I'm currently implementing a plugin that creates jobs and fills them with build 
steps.
I have a dropdown list for the different project types, and a repeatable field 
with dropboxes for the build steps available to the selected project.

Here's the jelly:

<j:jelly xmlns:j="jelly:core" xmlns:st="jelly:stapler" xmlns:d="jelly:define" 
xmlns:l="/lib/layout" xmlns:t="/lib/hudson"
  xmlns:f="/lib/form">

  <f:entry title="Projectname" field="${projectName}">
    <f:textbox />
  </f:entry>
  <f:entry title="Build project after creation?" 
field="runProjectAfterCreation">
    <f:checkbox />
  </f:entry>
  <f:entry field="projectType" title="Project / Job Type">
    <f:select default="noTypeSelected" />
  </f:entry>


  <f:entry title="Build Steps">
    <f:repeatable var="buildSteps" items="${instance.buildSteps}" minimum="1">
      <table width="100%" bgcolor="#EEEEEE">
        <div width="100%">
          <f:entry field="BuildStepType">
            <f:select default="noBuildStepSelected" />
            <f:repeatableDeleteButton value="Delete Build Step" />
          </f:entry>
        </div>
      </table>
    </f:repeatable>
  </f:entry>
</j:jelly>

And here's the java code of the plugin (Left some unrelated code out...):

public class JobCreator extends Builder {

    private final String       projectName;
    private final String       projectType;
    private final boolean      runProjectAfterCreation;
    private final List<String> buildSteps;

    // Fields in config.jelly must match the parameter names in the 
"DataBoundConstructor"
    @DataBoundConstructor
    public JobCreator( final String projectName, final boolean 
runProjectAfterCreation, final String projectType,
            final List<String> buildSteps ) {
        this.projectName = projectName;
        this.runProjectAfterCreation = runProjectAfterCreation;
        this.projectType = projectType;
        this.buildSteps = buildSteps;
    }

    public String getJobName() // ...
    public boolean getRunJobAfterCreation() // ...
    public String getProjectType() // ...
    public List<String> getBuildSteps() // ...

    @Override
    public boolean perform( final AbstractBuild<?, ?> build, final Launcher 
launcher, final BuildListener listener )
            throws AbortException {
        // ...
    }

    private void runProject( final AbstractProject<?, ?> project ) {
        // ...
    }

    // Overridden for better type safety.
    // If your plugin doesn't really define any property on Descriptor,
    // you don't have to do this.
    @Override
    public Descriptor getDescriptor() {
        return (Descriptor) super.getDescriptor();
    }

    @Extension
    public static final class Descriptor extends BuildStepDescriptor<Builder> {

        public Descriptor() {
            load();
        }

        public FormValidation doCheckJobName( @QueryParameter final String 
value ) throws IOException, ServletException {
            // ...
        }

        // Is overridden, so we have to use the raw type
        @SuppressWarnings( "rawtypes" )
        @Override
        public boolean isApplicable( final Class<? extends AbstractProject> 
aClass ) {
            // Indicates that this builder can be used with all kinds of 
project types
            return true;
        }

        @Override
        public String getDisplayName() {
            return "Create new Job";
        }

        public ListBoxModel doFillProjectTypeItems() {
            ListBoxModel items = new ListBoxModel();
            items.add( "Bitte Projekttyp wählen", "noTypeSelected" );
            for ( TopLevelItemDescriptor tliDescriptor : getAvailableJobTypes() 
) {
                items.add( tliDescriptor.getDisplayName(), 
tliDescriptor.getId() );
            }
            return items;

        }

        /**
         * Fills the dropbox "buildStepType" with the available build steps
         */
        @SuppressWarnings( "unchecked" )
        public ListBoxModel doFillBuildStepTypeItems( @QueryParameter final 
String projectType ) {
            ListBoxModel items = new ListBoxModel();

            // THROWS A NULL POINTER EXCEPTION IN THIS IF BLOCK

            if ( ( !projectType.equals( "noTypeSelected" ) ) && ( 
!projectType.equals( "hudson.maven.MavenModuleSet" ) ) ) {
                try {
                    for ( BuildStepDescriptor<? extends Builder> buildStep : 
getAvailableBuilders( (Class<? extends AbstractProject<?, ?>>) Class
                            .forName( projectType ).asSubclass( 
AbstractProject.class ) ) ) {
                        items.add( buildStep.getDisplayName(), 
buildStep.getId() );
                    }
                } catch ( ClassNotFoundException ex ) {
                    throw new RuntimeException( ex );
                }
                // Maven projects will throw a java.lang.ClassNotFoundException
            } else if ( projectType.equals( "hudson.maven.MavenModuleSet" ) ) {
                items.add( "Mavenprojekte werden nicht unterstützt!", 
"mavenSelected" );
            } else {
                items.add( "Bitte erst Projekttyp wählen!", "noProjectType" );
            }
            return items;
        }

        private List<BuildStepDescriptor<? extends Builder>> 
getAvailableBuilders(
                final Class<? extends AbstractProject<?, ?>> projectType ) {
            List<BuildStepDescriptor<? extends Builder>> builders = new 
ArrayList<BuildStepDescriptor<? extends Builder>>();

            // Add all build steps which are applicable to the project type and 
which have a DataBoundConstructor to the
            // list
            for ( hudson.model.Descriptor<Builder> descriptor : Builder.all() ) 
{
                if ( !( descriptor instanceof BuildStepDescriptor ) ) {
                    continue;
                }
                BuildStepDescriptor<? extends Builder> buildStepDescriptor = 
(BuildStepDescriptor<? extends Builder>) descriptor;
                if ( buildStepDescriptor.isApplicable( projectType ) && hasDbc( 
buildStepDescriptor.clazz ) ) {
                    builders.add( buildStepDescriptor );
                }
            }
            return builders;
        }

        private List<TopLevelItemDescriptor> getAvailableJobTypes() {
            List<TopLevelItemDescriptor> tlis = new 
ArrayList<TopLevelItemDescriptor>();
            for ( TopLevelItemDescriptor tliDescriptor : Items.all() ) {
                tlis.add( tliDescriptor );
            }
            return tlis;
        }

        private boolean hasDbc( final Class<?> clazz ) {
            for ( Constructor<?> constructor : clazz.getConstructors() ) {
                if ( constructor.isAnnotationPresent( 
DataBoundConstructor.class ) ) {
                    return true;
                }
            }
            return false;
        }

        @Override
        public boolean configure( final StaplerRequest req, final JSONObject 
formData ) throws FormException {
            save();
            return super.configure( req, formData );
        }
    }
}

If you need additional code (I commented/left some lines out), please tell me 
so.

Jenkins throws a java.lang.reflect.InvocationTargetException caused by a 
java.lang.NullPointerException at line 218 
(JobCreator$Descriptor.doFillBuildStepTypeItems, I marked it in the code 
excerpt)

Debugging the method shows that the QueryParameter projectType is null. The 
method also isn't called when I select a value from the project type dropdown 
list.

Can somebody help me with this?

Thanks in advance,
Sebastian

-- 
You received this message because you are subscribed to the Google Groups 
"Jenkins Developers" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
For more options, visit https://groups.google.com/d/optout.

Reply via email to