Able to subclass domain objects in Gradle Plugin DSL?

Hello,

I am working on a Gradle Plugin DSL. I would like to know if I there is a way to use subclasses of domain objects in my DSL. For example, I would like my DSL to do conceptually something like:

jobs {
  BaseJob 'job1' {
    propertyA = "a"
  }
  ExtendedJob 'job2' {
    propertyA = "a"
    propertyB = "b"
  }
}

where in my plugin, I have something like:

class MyJobPlugin implements Plugin<Project> {
  void apply(Project project) {
    def jobs = project.container(BaseJob)
    project.extensions.jobs = jobs
  }
}
  // and my classes look like:
  class BaseJob {
  String name;
  String propertyA;
}
  class ExtendedJob extends BaseJob {
  String propertyB;
}

I think I can do something like this by using the NamedDomainObjectContainer.create() method that accepts a NamedDomainObjectFactory, by doing something hacky like naming my objects with a prefix name that is the class to be created, like “BaseJob-job1” and “ExtendedJob-job2” and then parsing out the class name. Obviously, this is less desirable than some way to specify exactly what class to create in the DSL itself.

Thanks, Alex

That’s what ‘PolymorphicDomainObjectContainer’ is for, but there isn’t currently a public API for creating such a container.

I’m open to suggestions! Just FYI, I am a software engineer at LinkedIn - I’ll see if Szczepan has any ideas.

Just to tie off on this - instead of using containers, I wrote an extension class. My extension classes look like:

class MyJobPlugin implements Plugin<Project> {
  void apply(Project project) {
    project.extensions.add("jobs", new JobsExtension(project))
  }
}
  class JobsExtension {
  final List<BaseJob> jobs;
  final Project project;
    JobsExtension(Project project) {
    this.jobs = new ArrayList<BaseJob>();
    this.project = project;
  }
    BaseJob configureAndAdd(BaseJob job, Closure configure) {
    project.configure(job, configure);
    jobs.add(job);
    return job;
  }
  BaseJob baseJob(String name, Closure configure) {
    return configureAndAdd(new BaseJob(name), configure);
  }
  ExtendedJob extendedJob(Closure configure) {
    return configureAndAdd(new ExtendedJob(), configure);
  }
}

and then my DSL looks like:

jobs {
  baseJob('job1') {
    propertyA = "a"
  }
  extendedJob('job2') {
    propertyA = "a"
    propertyB = "b"
  }
}

With this solution, the DSL is still pretty nice and the extension classes are straightforward (no containers, no internal API, etc).