XML Manipulation

I am trying to create a Maven pom.xml file problematically through the Psi interface. I'm just trying basic modifications, but I can't get anything to write. I am running everything in an

ApplicationManager.getApplication().runWriteAction(() -> { ... });

block. 

I try this code:

XmlTag root = pomXmlFile.getRootTag();
XmlTag tag = root.createChildTag("artifactId", "http://maven.apache.org/POM/4.0.0", "test", false);
System.out.println(root);
System.out.println(tag);
root.addSubTag(tag, false);

and as output from the two System.out.println's I get:

XmlTag:project
XmlTag:artifactId

so neither one is null. However, on the 5th line I get:

java.lang.NullPointerException
at com.intellij.psi.impl.source.tree.ChangeUtil.decodeInformation(ChangeUtil.java:87)
at com.intellij.psi.impl.source.tree.ChangeUtil.decodeInformation(ChangeUtil.java:79)
at com.intellij.psi.impl.source.tree.CompositePsiElement.addAfter(CompositePsiElement.java:164)
at com.intellij.psi.impl.source.xml.XmlTagImpl.addSubTag(XmlTagImpl.java:1059)
at com.demonwav.mcdev.buildsystem.maven.MavenBuildSystem.lambda$create$0(MavenBuildSystem.java:147)
at com.intellij.openapi.application.impl.ApplicationImpl.runWriteAction(ApplicationImpl.java:1009)
at com.demonwav.mcdev.buildsystem.maven.MavenBuildSystem.create(MavenBuildSystem.java:113)
at com.demonwav.mcdev.creator.MavenProjectCreator.create(MavenProjectCreator.java:69)
at com.intellij.ide.startup.impl.StartupManagerImpl.runActivity(StartupManagerImpl.java:344)
at com.intellij.ide.startup.impl.StartupManagerImpl.runActivities(StartupManagerImpl.java:336)
at com.intellij.ide.startup.impl.StartupManagerImpl.runPostStartupActivities(StartupManagerImpl.java:184)
at com.intellij.openapi.project.impl.ProjectManagerImpl$5$2.run(ProjectManagerImpl.java:393)
at com.intellij.openapi.application.impl.LaterInvocator$FlushQueue.runNextEvent(LaterInvocator.java:345)
at com.intellij.openapi.application.impl.LaterInvocator$FlushQueue.run(LaterInvocator.java:329)
at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:311)
at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:756)
at java.awt.EventQueue.access$500(EventQueue.java:97)
at java.awt.EventQueue$3.run(EventQueue.java:709)
at java.awt.EventQueue$3.run(EventQueue.java:703)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:76)
at java.awt.EventQueue.dispatchEvent(EventQueue.java:726)
at com.intellij.ide.IdeEventQueue.defaultDispatchEvent(IdeEventQueue.java:857)
at com.intellij.ide.IdeEventQueue._dispatchEvent(IdeEventQueue.java:658)
at com.intellij.ide.IdeEventQueue.dispatchEvent(IdeEventQueue.java:386)
at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:201)
at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:116)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:105)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:93)
at java.awt.EventDispatchThread.run(EventDispatchThread.java:82)

So I try something else instead. I built the interface tree described here http://www.jetbrains.org/intellij/sdk/docs/reference_guide/frameworks_and_external_apis/xml_dom_api.html and ran this code:

DomManager.getDomManager(project);
MavenProject mavenProject = DomManager.getDomManager(project).getFileElement(pomXmlFile, MavenProject.class, "project").getRootElement();
mavenProject.getArtifactId().setValue("test");

and I get two exceptions on the last line:

com.intellij.util.IncorrectOperationException: Element cannot be added
at com.intellij.psi.impl.source.tree.CompositePsiElement.addInnerBefore(CompositePsiElement.java:322)
at com.intellij.psi.impl.source.tree.CompositePsiElement.add(CompositePsiElement.java:151)
at com.intellij.util.xml.impl.IndexedElementInvocationHandler$1.run(IndexedElementInvocationHandler.java:95)
at com.intellij.util.xml.impl.DomManagerImpl.runChange(DomManagerImpl.java:313)
at com.intellij.util.xml.impl.IndexedElementInvocationHandler.setEmptyXmlTag(IndexedElementInvocationHandler.java:90)
at com.intellij.util.xml.impl.DomInvocationHandler.ensureTagExists(DomInvocationHandler.java:270)
at com.intellij.util.xml.impl.DomInvocationHandler.setValue(DomInvocationHandler.java:149)
at com.intellij.util.xml.impl.SetInvocation.invoke(SetInvocation.java:47)
at com.intellij.util.xml.impl.DomInvocationHandler.invoke(DomInvocationHandler.java:689)
at com.demonwav.mcdev.buildsystem.maven.pom.ArtifactId$$EnhancerByCGLIB$$9385a3fd.setValue(<generated>)
at com.demonwav.mcdev.buildsystem.maven.MavenBuildSystem.lambda$create$0(MavenBuildSystem.java:139)
at com.intellij.openapi.application.impl.ApplicationImpl.runWriteAction(ApplicationImpl.java:1009)
at com.demonwav.mcdev.buildsystem.maven.MavenBuildSystem.create(MavenBuildSystem.java:113)
at com.demonwav.mcdev.creator.MavenProjectCreator.create(MavenProjectCreator.java:69)
at com.intellij.ide.startup.impl.StartupManagerImpl.runActivity(StartupManagerImpl.java:344)
at com.intellij.ide.startup.impl.StartupManagerImpl.runActivities(StartupManagerImpl.java:336)
at com.intellij.ide.startup.impl.StartupManagerImpl.runPostStartupActivities(StartupManagerImpl.java:184)
at com.intellij.openapi.project.impl.ProjectManagerImpl$5$2.run(ProjectManagerImpl.java:393)
at com.intellij.openapi.application.impl.LaterInvocator$FlushQueue.runNextEvent(LaterInvocator.java:345)
at com.intellij.openapi.application.impl.LaterInvocator$FlushQueue.run(LaterInvocator.java:329)
at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:311)
at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:756)
at java.awt.EventQueue.access$500(EventQueue.java:97)
at java.awt.EventQueue$3.run(EventQueue.java:709)
at java.awt.EventQueue$3.run(EventQueue.java:703)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:76)
at java.awt.EventQueue.dispatchEvent(EventQueue.java:726)
at com.intellij.ide.IdeEventQueue.defaultDispatchEvent(IdeEventQueue.java:857)
at com.intellij.ide.IdeEventQueue._dispatchEvent(IdeEventQueue.java:658)
at com.intellij.ide.IdeEventQueue.dispatchEvent(IdeEventQueue.java:386)
at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:201)
at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:116)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:105)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:93)
at java.awt.EventDispatchThread.run(EventDispatchThread.java:82)

java.lang.IllegalArgumentException: Argument for @NotNull parameter 'psi' of com/intellij/semantic/SemServiceImpl.setCachedSemElement must not be null
at com.intellij.semantic.SemServiceImpl.setCachedSemElement(SemServiceImpl.java)
at com.intellij.util.xml.impl.DomManagerImpl.cacheHandler(DomManagerImpl.java:159)
at com.intellij.util.xml.impl.DomInvocationHandler.ensureTagExists(DomInvocationHandler.java:276)
at com.intellij.util.xml.impl.DomInvocationHandler.setValue(DomInvocationHandler.java:149)
at com.intellij.util.xml.impl.SetInvocation.invoke(SetInvocation.java:47)
at com.intellij.util.xml.impl.DomInvocationHandler.invoke(DomInvocationHandler.java:689)
at com.demonwav.mcdev.buildsystem.maven.pom.ArtifactId$$EnhancerByCGLIB$$9385a3fd.setValue(<generated>)
at com.demonwav.mcdev.buildsystem.maven.MavenBuildSystem.lambda$create$0(MavenBuildSystem.java:139)
at com.intellij.openapi.application.impl.ApplicationImpl.runWriteAction(ApplicationImpl.java:1009)
at com.demonwav.mcdev.buildsystem.maven.MavenBuildSystem.create(MavenBuildSystem.java:113)
at com.demonwav.mcdev.creator.MavenProjectCreator.create(MavenProjectCreator.java:69)
at com.intellij.ide.startup.impl.StartupManagerImpl.runActivity(StartupManagerImpl.java:344)
at com.intellij.ide.startup.impl.StartupManagerImpl.runActivities(StartupManagerImpl.java:336)
at com.intellij.ide.startup.impl.StartupManagerImpl.runPostStartupActivities(StartupManagerImpl.java:184)
at com.intellij.openapi.project.impl.ProjectManagerImpl$5$2.run(ProjectManagerImpl.java:393)
at com.intellij.openapi.application.impl.LaterInvocator$FlushQueue.runNextEvent(LaterInvocator.java:345)
at com.intellij.openapi.application.impl.LaterInvocator$FlushQueue.run(LaterInvocator.java:329)
at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:311)
at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:756)
at java.awt.EventQueue.access$500(EventQueue.java:97)
at java.awt.EventQueue$3.run(EventQueue.java:709)
at java.awt.EventQueue$3.run(EventQueue.java:703)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:76)
at java.awt.EventQueue.dispatchEvent(EventQueue.java:726)
at com.intellij.ide.IdeEventQueue.defaultDispatchEvent(IdeEventQueue.java:857)
at com.intellij.ide.IdeEventQueue._dispatchEvent(IdeEventQueue.java:658)
at com.intellij.ide.IdeEventQueue.dispatchEvent(IdeEventQueue.java:386)
at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:201)
at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:116)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:105)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:93)
at java.awt.EventDispatchThread.run(EventDispatchThread.java:82)

This is the basis pom.xml file I'm working with:

<?xml version="1.0" encoding="UTF-8"?>

<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<build>
<plugins>
<plugin>
<version>3.1</version>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.7</source>
<target>1.7</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>2.3</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<minimizeJar>true</minimizeJar>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

What am I doing wrong? Thanks.

7 comments

Hi Kyle,

One thing you could try is 

new WriteCommandAction.Simple(project, psiFile) {
@Override
protected void run() throws Throwable {
XmlTag root = pomXmlFile.getRootTag();
XmlTag subTag = rootTag.addSubTag(root.createChildTag("artifactId", "http://maven.apache.org/POM/4.0.0", null, false), false);
}
}.execute();

In here, project variable should be your Project and psiFile is the PsiFile instance of the file you are trying to manipulate (poXmlFile)

0

When I run that code I just get the

Assertion failed: Write access is allowed inside write-action only (see com.intellij.openapi.application.Application.runWriteAction())

error, whether I wrap it in 

ApplicationManager.getApplication().runWriteAction(() -> { ... });

or not.

0

Never mind, I forgot I was creating the file earlier. Here is the whole code block:

PsiFile pomPsi = PsiFileFactory.getInstance(project).createFileFromText(XMLLanguage.INSTANCE, BukkitTemplate.applyPomTemplate(project, "1.7"));
pomPsi.setName("pom.xml");

new WriteCommandAction.Simple(project, pomPsi) {
@Override
protected void run() throws Throwable {
PsiDirectory rootDirectoryPsi = PsiManager.getInstance(project).findDirectory(rootDirectory);

if (rootDirectoryPsi != null) {
rootDirectoryPsi.add(pomPsi);

pomFile = rootDirectory.findChild("pom.xml");

XmlFile pomXmlFile = (XmlFile) pomPsi;

DomManager manager = DomManager.getDomManager(project);
MavenProject mavenProject = manager.getFileElement(pomXmlFile, MavenProject.class, "project").getRootElement();
mavenProject.getArtifactId().setValue("test");
}
}
}.execute();

and I got this exception:

com.intellij.util.IncorrectOperationException: Must not change PSI outside command or undo-transparent action. See com.intellij.openapi.command.WriteCommandAction or com.intellij.openapi.command.CommandProcessor
at com.intellij.pom.core.impl.PomModelImpl.startTransaction(PomModelImpl.java:329)
at com.intellij.pom.core.impl.PomModelImpl.runTransaction(PomModelImpl.java:146)
at com.intellij.psi.impl.source.xml.XmlTextImpl.doSetValue(XmlTextImpl.java:185)
at com.intellij.psi.impl.source.xml.XmlTextImpl.setValue(XmlTextImpl.java:179)
at com.intellij.psi.impl.source.xml.XmlTagValueImpl.setText(XmlTagValueImpl.java:131)
at com.intellij.psi.impl.source.xml.XmlTagValueImpl.setText(XmlTagValueImpl.java:106)
at com.intellij.util.xml.impl.DomInvocationHandler.setTagValue(DomInvocationHandler.java:725)
at com.intellij.util.xml.impl.DomInvocationHandler.access$000(DomInvocationHandler.java:65)
at com.intellij.util.xml.impl.DomInvocationHandler$1.run(DomInvocationHandler.java:153)
at com.intellij.util.xml.impl.DomManagerImpl.runChange(DomManagerImpl.java:313)
at com.intellij.util.xml.impl.DomInvocationHandler.setValue(DomInvocationHandler.java:150)
at com.intellij.util.xml.impl.SetInvocation.invoke(SetInvocation.java:47)
at com.intellij.util.xml.impl.DomInvocationHandler.invoke(DomInvocationHandler.java:689)
at com.demonwav.mcdev.buildsystem.maven.pom.ArtifactId$$EnhancerByCGLIB$$6d0b8655.setValue(<generated>)
at com.demonwav.mcdev.buildsystem.maven.MavenBuildSystem.lambda$create$0(MavenBuildSystem.java:176)
at com.intellij.openapi.application.impl.ApplicationImpl.runWriteAction(ApplicationImpl.java:1009)
at com.demonwav.mcdev.buildsystem.maven.MavenBuildSystem.create(MavenBuildSystem.java:161)
at com.demonwav.mcdev.creator.MavenProjectCreator.create(MavenProjectCreator.java:69)
at com.intellij.ide.startup.impl.StartupManagerImpl.runActivity(StartupManagerImpl.java:344)
at com.intellij.ide.startup.impl.StartupManagerImpl.runActivities(StartupManagerImpl.java:336)
at com.intellij.ide.startup.impl.StartupManagerImpl.runPostStartupActivities(StartupManagerImpl.java:184)
at com.intellij.openapi.project.impl.ProjectManagerImpl$5$2.run(ProjectManagerImpl.java:393)
at com.intellij.openapi.application.impl.LaterInvocator$FlushQueue.runNextEvent(LaterInvocator.java:345)
at com.intellij.openapi.application.impl.LaterInvocator$FlushQueue.run(LaterInvocator.java:329)
at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:311)
at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:756)
at java.awt.EventQueue.access$500(EventQueue.java:97)
at java.awt.EventQueue$3.run(EventQueue.java:709)
at java.awt.EventQueue$3.run(EventQueue.java:703)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:76)
at java.awt.EventQueue.dispatchEvent(EventQueue.java:726)
at com.intellij.ide.IdeEventQueue.defaultDispatchEvent(IdeEventQueue.java:857)
at com.intellij.ide.IdeEventQueue._dispatchEvent(IdeEventQueue.java:658)
at com.intellij.ide.IdeEventQueue.dispatchEvent(IdeEventQueue.java:386)
at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:201)
at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:116)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:105)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:93)
at java.awt.EventDispatchThread.run(EventDispatchThread.java:82)

 

 

0

Okay, after putting that code above in a runWriteAction block with the file creation in that runWriteAction block and the rest in the WriteCommandAction.Simple, it works. I still don't really understand why, but thanks for the help.

0

In 

new WriteCommandAction.Simple(project, pomPsi) { ... }

is the code run asynchronously? If so, is there a way to wait for it to finish? It seems like I'm getting a race condition with this.

0

I'm not sure, but the WriteCommandAction.Simple runs asynchronously. Best approach for your solution is to create the pom.xml file with all the necessary xml tags within it. When you are creating the file from Text, change the text appropriately, prior to creating the file. (replace variable placeholders with actual values in the text template.)

0

Thank you, I can't believe I didn't think of that. Changing the order worked perfectly.

0

Please sign in to leave a comment.