how to use/create a gradle custom model?

Hi,

I'm trying to add gradle support to a plugin and I need some additional information from a gradle plugin.
The gradle way to provide this information is to use a custom model (org.gradle.tooling.model.Model).

So far, I tried the following:

Based on org.jetbrains.plugins.gradle.tooling.internal.ExtraModelBuilder I have created a ModelBuilder
that implements ModelBuilderService.

I also have a META-INF/services/org.jetbrains.plugins.gradle.tooling.ModelBuilderService file.

I then tried the following code (inside an actionPerformed(AnActionEvent e) ) to get the custom model:

GradleExecutionSettings executionSettings = ExternalSystemApiUtil.getExecutionSettings(p, p.getBasePath(), GradleConstants.SYSTEM_ID);
executionSettings.setVerboseProcessing(true);

GradleExecutionHelper helper = new GradleExecutionHelper();
FooModel fooToolingModel = helper.execute(p.getBasePath(), executionSettings, new Function<ProjectConnection, FooModel>() {
    @Override
    public FooModel fun(ProjectConnection projectConnection) {
        return projectConnection.getModel(FooModel.class);
    }
});

which fails with:
No builders are available to build a model of type '<package>.FooModel'


Looking at the code of GradleExecutionHelper.execute() it does not use generateInitScript() which is probably the
reason it does fail.

How do I get an instance of my gradle custom model from a plugin?

3 comments
Comment actions Permalink

Hi, Martin,

there is no such an API to request custom model on demand in Jetbrains gradle plugin (feel free to request it at https://youtrack.jetbrains.com).

But, you can plug into the gradle project import using projectResolve extension point for that purpose.

Add the your projectResolve to your plugin.xml:

<extensions defaultExtensionNs="org.jetbrains.plugins.gradle">
  <projectResolve implementation="my.package.MyCustomPluginProjectResolverExtension"/>
</extensions>


here is a simple implementation of such projectResolve:

 

package my.package;

import com.intellij.openapi.externalSystem.model.DataNode;
import com.intellij.openapi.externalSystem.model.project.ModuleData;
import com.intellij.openapi.externalSystem.util.ExternalSystemConstants;
import com.intellij.openapi.externalSystem.util.Order;
import com.intellij.util.containers.ContainerUtil;
import org.gradle.tooling.model.idea.IdeaModule;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.plugins.gradle.service.project.AbstractProjectResolverExtension;

import java.util.Collections;
import java.util.Set;

@Order(ExternalSystemConstants.UNORDERED)
public class FooModelPluginProjectResolverExtension extends AbstractProjectResolverExtension {

  @Override
  public void
populateModuleExtraModels(@NotNull IdeaModule gradleModule, @NotNull DataNode<ModuleData> ideModule) {
    FooModel myModel = resolverCtx.getExtraProject(gradleModule, FooModel.class);
    if (myModel != null) {
      // do something or store for further processing
    
}
    nextResolver.populateModuleExtraModels(gradleModule, ideModule);
  }

  @NotNull
  @Override
  public
Set<Class> getExtraProjectModelClasses() {
    return Collections.<Class>singleton(FooModel.class);
  }

  @NotNull
  @Override
  public
Set<Class> getToolingExtensionsClasses() {
    return ContainerUtil.<Class>set(
     FooModelBuilderImpl.class
    
);
  }
}
0
Comment actions Permalink

Thanks, this helped :)

Unfortunately it still does not work. Idea doesn't pick up my ModelBuilder.
I have stepped into gradle and when it calls the ExtraModelBuilder it does not have my own builder in the buildersLoader list.

Is

getToolingExtensionsClasses()


required to pick up the Builder or should Idea find the Builder just by having  a src/main/resources/META-INF/services/org.jetbrains.plugins.gradle.tooling.ModelBuilderService file?

getToolingExtensionClasses() does not (yet) exists in 135 (I'm using 135 because the communit edition is 135).


Is there a way to find out why ServiceLoader<ModelBuilderService> isn't picking up my own builder? Will it scan my plugin at all (maybe ExtraModelBuilder is created before Idea loads
the plugin...)?

Martin

0
Comment actions Permalink

getToolingExtensionsClasses() method used to find jar files containing the classes and to add it to ExtraModelBuilder's classloader.
After that, services defined in /META-INF/services/org.jetbrains.plugins.gradle.tooling.ModelBuilderService files will be available for ExtraModelBuilder service loader.

This approach to extend IDEA gradle plugin (by other plugins) was introduced in IDEA 14 (139 branch), in 135 ModelBuilderServices used only for internal needs.

0

Please sign in to leave a comment.