IntelliJ Platform Framework Initialization Guide

This guide provides comprehensive documentation on how to initialize frameworks in IntelliJ Platform plugins, based on analysis of both official documentation and the Apache Struts plugin implementation.

Table of Contents

  1. Modern Framework Initialization (2025)
  2. Complete Framework Integration Architecture
  3. Implementation Patterns
  4. Best Practices
  5. Common Issues and Solutions
  6. Migration from Legacy Approaches

Modern Framework Initialization (2025)

ProjectActivity - The Current Standard

IntelliJ Platform 2024.2+ uses ProjectActivity as the modern replacement for deprecated initialization patterns.

Key Requirements:

  • Must be implemented with Kotlin coroutines (Java not supported for new implementations)
  • Register via <postStartupActivity implementation="..."/> extension point
  • Executes after project is opened with proper coroutine context

Example Registration:

<extensions defaultExtensionNs="com.intellij">
  <postStartupActivity implementation="com.example.MyFrameworkInitializer"/>
</extensions>

Deprecated Patterns (Avoid These)

  • Components: Deprecated, don't support dynamic loading
  • StartupActivity: Marked as @Obsolete
  • StartupManager.runAfterOpened(): Internal API, removed

Complete Framework Integration Architecture

The Apache Struts plugin demonstrates the comprehensive pattern for framework integration. Here are the core components:

1. FacetType

Defines the framework facet with metadata and capabilities.

public class StrutsFacetType extends FacetType<StrutsFacet, StrutsFacetConfiguration> {

  StrutsFacetType() {
    super(StrutsFacet.FACET_TYPE_ID, "Struts2", "Struts 2");
  }

  @Override
  public boolean isSuitableModuleType(final ModuleType moduleType) {
    return moduleType instanceof JavaModuleType;  // Restrict to Java modules
  }

  @Override
  public Icon getIcon() {
    return Struts2Icons.Action;
  }
}

Key Features:

  • Unique facet type ID
  • Module type restrictions
  • Icon and help topic configuration
  • Factory methods for facet and configuration creation

2. FacetConfiguration

Manages framework-specific settings and persistence. Implements PersistentStateComponent<Element> for XML serialization, which is the modern replacement for the deprecated readExternal/writeExternal methods.

public class StrutsFacetConfiguration extends SimpleModificationTracker
    implements FacetConfiguration, PersistentStateComponent<Element>, Disposable {

  @Override
  public FacetEditorTab[] createEditorTabs(final FacetEditorContext editorContext,
                                           final FacetValidatorsManager validatorsManager) {
    return new FacetEditorTab[]{
      new FileSetConfigurationTab(this, editorContext),
      new FeaturesConfigurationTab(this)
    };
  }

  @Override
  public @Nullable Element getState() {
    // Build and return JDOM Element representing current configuration
  }

  @Override
  public void loadState(@NotNull Element state) {
    // Restore configuration from JDOM Element
  }
}

Responsibilities:

  • Settings persistence via PersistentStateComponent (getState/loadState)
  • Editor tabs for configuration UI
  • Modification tracking
  • Resource disposal

3. Facet

The main facet class providing framework access at module level.

public class StrutsFacet extends Facet<StrutsFacetConfiguration> {

  public static final FacetTypeId<StrutsFacet> FACET_TYPE_ID = new FacetTypeId<>("struts2");

  @Nullable
  public static StrutsFacet getInstance(@NotNull final Module module) {
    return FacetManager.getInstance(module).getFacetByType(FACET_TYPE_ID);
  }

  @Nullable
  public WebFacet getWebFacet() {
    return FacetManager.getInstance(getModule()).getFacetByType(WebFacet.ID);
  }
}

Key Features:

  • Static access methods for convenience
  • Integration with other facets (e.g., WebFacet)
  • Module-scoped framework instance

4. FrameworkDetector

Automatically detects framework presence in projects.

public class StrutsFrameworkDetector extends FacetBasedFrameworkDetector<StrutsFacet, StrutsFacetConfiguration> {

  @Override
  public ElementPattern<FileContent> createSuitableFilePattern() {
    return FileContentPattern.fileContent()
      .withName(StrutsConstants.STRUTS_XML_DEFAULT_FILENAME)  // "struts.xml"
      .xmlWithRootTag(StrutsRoot.TAG_NAME);                   // <struts>
  }

  @Override
  public boolean isSuitableUnderlyingFacetConfiguration(final FacetConfiguration underlying,
                                                        final StrutsFacetConfiguration configuration,
                                                        final Set<? extends VirtualFile> files) {
    return underlying instanceof WebFacetConfiguration;  // Requires Web facet
  }
}

Detection Strategy:

  • File pattern matching (e.g., struts.xml with <struts> root)
  • Underlying facet validation
  • Multi-file detection support

5. FrameworkSupportProvider

Handles “Add Framework Support” dialog integration.

public class StrutsFrameworkSupportProvider extends FacetBasedFrameworkSupportProvider<StrutsFacet> {

  @Override
  public String getTitle() {
    return UIUtil.replaceMnemonicAmpersand("Struts &2");
  }

  @Override
  protected void onFacetCreated(final StrutsFacet strutsFacet,
                                final ModifiableRootModel modifiableRootModel,
                                final FrameworkVersion version) {
    // Trigger initialization after facet creation
  }
}

Capabilities:

  • Framework library management
  • Version selection UI
  • Integration with project setup wizard
  • Post-creation initialization trigger

6. Framework Initializer

Performs complex setup tasks after framework addition.

public class StrutsFrameworkInitializer implements ProjectActivity {

  @Override
  public Object execute(@NotNull Project project, @NotNull Continuation<? super Unit> continuation) {
    DumbService.getInstance(project).runWhenSmart(() -> {
      // Create default configuration files
      final FileTemplate strutsXmlTemplate = templateProvider.determineFileTemplate(project);
      final PsiElement strutsXml = FileTemplateUtil.createFromTemplate(strutsXmlTemplate, ...);

      // Configure web.xml if present
      WriteCommandAction.writeCommandAction(project).run(() -> {
        // Add filters and mappings
      });

      // Show completion notification
      new Notification("Framework Setup", "Framework has been configured successfully", ...)
        .notify(project);
    });
  }
}

Initialization Tasks:

  • Create default configuration files (struts.xml)
  • Configure web.xml with filters/mappings
  • Set up file sets for configuration discovery
  • Show user notifications
  • Handle error scenarios gracefully

Implementation Patterns

Plugin.xml Registration

<extensions defaultExtensionNs="com.intellij">
  <!-- Core Framework Components -->
  <facetType implementation="com.example.MyFacetType"/>
  <frameworkSupport implementation="com.example.MyFrameworkSupportProvider"/>
  <framework.detector implementation="com.example.MyFrameworkDetector"/>
  <library.type implementation="com.example.MyLibraryType"/>

  <!-- Modern Initialization -->
  <postStartupActivity implementation="com.example.MyFrameworkInitializer"/>
</extensions>

Initialization Sequence Flow

  1. Detection Phase: FrameworkDetector scans project files
  2. Support Addition: User adds framework via “Add Framework Support”
  3. Facet Creation: FrameworkSupportProvider creates facet and configuration
  4. Initialization: ProjectActivity performs setup tasks
  5. User Notification: Success/failure feedback shown

Integration with IntelliJ Services

// Index-dependent operations
DumbService.getInstance(project).runWhenSmart(() -> {
  // Search, analysis, file creation
});

// Write operations
WriteCommandAction.writeCommandAction(project).run(() -> {
  // File modifications
});

// File template usage
FileTemplate template = FileTemplateManager.getInstance(project)
  .getInternalTemplate("framework-config.xml");
PsiElement created = FileTemplateUtil.createFromTemplate(template, ...);

Best Practices

1. Robust Error Handling

try {
  // Framework initialization logic
} catch (Exception e) {
  LOG.error("Framework initialization failed", e);

  // Show user-friendly error notification
  Notifications.Bus.notify(new Notification(
    "Framework Setup",
    "Setup Failed",
    "Framework setup encountered an error: " + e.getMessage(),
    NotificationType.ERROR
  ), project);
}

2. User Communication

// Success notification with actionable links
NotificationListener showSettingsListener = (notification, event) -> {
  if (event.getEventType() == HyperlinkEvent.EventType.ACTIVATED) {
    notification.expire();
    ModulesConfigurator.showFacetSettingsDialog(facet, null);
  }
};

new Notification("Framework Setup", "Setup Complete",
  "Framework configured successfully. <a href=\"settings\">Review settings</a>",
  NotificationType.INFORMATION)
  .setListener(showSettingsListener)
  .notify(project);

3. Incremental Initialization

// Check if already initialized
if (existingConfigFile != null) {
  LOG.info("Framework already configured, skipping initialization");
  return;
}

// Verify prerequisites
if (requiredFacet == null) {
  LOG.warn("Required underlying facet not found, postponing initialization");
  return;
}

4. Resource Management

public class MyFacetConfiguration extends SimpleModificationTracker
    implements FacetConfiguration, PersistentStateComponent<Element>, Disposable {

  @Override
  public void dispose() {
    // Clean up resources, listeners, etc.
  }
}

// Register for disposal
Disposer.register(facet, configuration);

Common Issues and Solutions

Issue: ProjectActivity Not Executing

Symptoms: Framework initializer never runs Cause: Missing plugin.xml registration or incorrect extension point Solution:

<postStartupActivity implementation="com.example.MyFrameworkInitializer"/>

Issue: Dumb Mode Errors

Symptoms: Index-related exceptions during initialization Cause: Accessing indices while IntelliJ is indexing Solution:

DumbService.getInstance(project).runWhenSmart(() -> {
  // Index-dependent logic here
});

Issue: Framework Not Auto-Detected

Symptoms: Framework detector doesn't trigger Cause: Incorrect file pattern or missing registration Solution:

@Override
public ElementPattern<FileContent> createSuitableFilePattern() {
  return FileContentPattern.fileContent()
    .withName("framework-config.xml")  // Exact filename
    .xmlWithRootTag("framework");      // XML root element
}

Issue: Facet Creation Fails

Symptoms: “Add Framework Support” fails silently Cause: Unsuitable module type or missing underlying facets Solution:

@Override
public boolean isSuitableModuleType(final ModuleType moduleType) {
  return moduleType instanceof JavaModuleType;  // Be specific
}

@Override
public boolean isSuitableUnderlyingFacetConfiguration(...) {
  return underlying instanceof RequiredFacetConfiguration;
}

Migration from Legacy Approaches

From StartupActivity to ProjectActivity

Legacy (Deprecated):

public class OldInitializer implements StartupActivity {
  @Override
  public void runActivity(@NotNull Project project) {
    // Old initialization logic
  }
}

Modern (Recommended):

// Kotlin implementation required for new code
class ModernInitializer : ProjectActivity {
  override suspend fun execute(project: Project) {
    withContext(Dispatchers.IO) {
      // Initialization logic with coroutines
    }
  }
}

From Components to Services

Legacy (Deprecated):

<project-components>
  <component>
    <implementation-class>com.example.ProjectComponent</implementation-class>
  </component>
</project-components>

Modern (Recommended):

<extensions defaultExtensionNs="com.intellij">
  <projectService serviceImplementation="com.example.ProjectService"/>
</extensions>

Conclusion

Framework initialization in modern IntelliJ Platform plugins requires:

  1. Complete Architecture: Facet + Configuration + Detector + Support Provider + Initializer
  2. Modern APIs: ProjectActivity with Kotlin coroutines (for new implementations)
  3. Proper Registration: All components registered in plugin.xml
  4. Robust Implementation: Error handling, user communication, resource management
  5. Testing: Verification across different project configurations

The Apache Struts plugin provides an excellent reference implementation, though it still uses Java-based ProjectActivity which is acceptable for existing code but should be migrated to Kotlin for new implementations.

For questions or issues, consult: