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.
IntelliJ Platform 2024.2+ uses ProjectActivity as the modern replacement for deprecated initialization patterns.
Key Requirements:
<postStartupActivity implementation="..."/> extension pointExample Registration:
<extensions defaultExtensionNs="com.intellij"> <postStartupActivity implementation="com.example.MyFrameworkInitializer"/> </extensions>
@ObsoleteThe Apache Struts plugin demonstrates the comprehensive pattern for framework integration. Here are the core components:
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:
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:
PersistentStateComponent (getState/loadState)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:
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:
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:
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:
<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>
FrameworkDetector scans project filesFrameworkSupportProvider creates facet and configurationProjectActivity performs setup tasks// 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, ...);
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); }
// 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);
// 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; }
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);
Symptoms: Framework initializer never runs Cause: Missing plugin.xml registration or incorrect extension point Solution:
<postStartupActivity implementation="com.example.MyFrameworkInitializer"/>
Symptoms: Index-related exceptions during initialization Cause: Accessing indices while IntelliJ is indexing Solution:
DumbService.getInstance(project).runWhenSmart(() -> { // Index-dependent logic here });
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 }
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; }
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 } } }
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>
Framework initialization in modern IntelliJ Platform plugins requires:
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: