How to change PSIClass (java files) ?
Hello,
I am trying to parse some java code and modify some of it's contents (method names, variable types) and currently I can iterate through all .java files on the project folder but now I can't change the text content of the PSI Class referring to the .java file since there is no setText() method in the PsiClass class. Here is my current code:
// Translation will be made here
Processor<PsiClass> processor = new Processor<PsiClass>() {
@Override
public boolean process(PsiClass psiClass) {
// Do work here
System.out.println(psiClass.getText());
return true;
}
};
// Get all JavaClasses on project folder
AllClassesGetter.processJavaClasses(
new PlainPrefixMatcher(""),
project,
GlobalSearchScope.projectScope(project),
processor
);
Please sign in to leave a comment.
Yes
I did as you said and it worked but I have a small problem that I can't fix when I add the ImportStatement (code below).
public void addPackage(PsiJavaFile javaFile,Project project){
//Adds package name
String newPackage = "org.onepf.oms";
PsiPackageStatement newStatement;
newStatement = JavaPsiFacade.getElementFactory(project).createPackageStatement(newPackage);
PsiImportStatement[] list= javaFile.getImportList().getImportStatements();
int firstPosition = 0 ;
PsiImportStatement firstImport = list[firstPosition];
javaFile.addBefore(newStatement,firstImport); (ERROR here also -> Assertion failed: anchorBefore == null || anchorBefore.getTreeParent() == parent
java.lang.Throwable)
}
The only problem is that the result I get is the import and the package on the same line like this:
Any idea on how to fix this? ( I tried adding "/n" to the package name but since the ";" is applied after by the createPackageStatement method it won't work)
Have you tried PsiJavaFile#setPackageName, is it better?
Yes, it worked if I kept using the Runnable object. Thank you for your help!
When iterating through the file methods and fields, if I change one of them like this:
public void addField(PsiJavaFile javaFile, Project project,PsiField field){String newFieldValue="IOpenInAppBillingService mService;";
PsiField newField;
newField = JavaPsiFacade.getElementFactory(project).createFieldFromText(newFieldValue,javaFile);
field.replace(newField);
}
I end up having this error:
java.lang.AssertionError: Next sibling of the element 'PsiField:mService' changed. Was: PsiWhiteSpace; Now:null; Root:PsiClass:TextBoxes
Any idea on how to avoid this?
It'd be easier to answer if you quoted both the exception message and the stack trace. I suspect that you get this from recursive visitor internals. The fix is to do the change not inside the visitor, but use it only to accumulate all elements you need to change, and then modify them after traversing the PSI.
It makes a lot of sense, I will try to save all elements to be changed and only modify them after the iteration.
I am trying to change a method's body but I get this error while running the plugin:
file/doc text length different, File[PsiJavaFile:IabHelper.java IabHelper.java, Language: JAVA, SingleRootFileViewProvider{myVirtualFile=file:///home/guilhermeandraade/Desktop/android-play-billing-master/TrivialDrive/app/src/main/java/com/example/android/trivialdrivesample/util/IabHelper.java, content=com.intellij.psi.SingleRootFileViewProvider$PsiFileContent@100927be}] file.length=50042; doc.length=50046java.lang.Throwable
at com.intellij.openapi.diagnostic.Logger.error(Logger.java:127)
at com.intellij.psi.formatter.FormattingDocumentModelImpl.checkDocument(FormattingDocumentModelImpl.java:75)
at com.intellij.psi.formatter.FormattingDocumentModelImpl.createOn(FormattingDocumentModelImpl.java:65)
at com.intellij.lang.java.JavaFormattingModelBuilder.createModel(JavaFormattingModelBuilder.java:58)
at com.intellij.formatting.CoreFormatterUtil.buildModel(CoreFormatterUtil.java:48)
at com.intellij.psi.impl.source.codeStyle.CodeFormatterFacade.processText(CodeFormatterFacade.java:236)
at com.intellij.psi.impl.source.PostprocessReformattingAspect$ReformatRangesAction.execute(PostprocessReformattingAspect.java:730)
at com.intellij.psi.impl.source.PostprocessReformattingAspect.doPostponedFormattingInner(PostprocessReformattingAspect.java:338)
at com.intellij.psi.impl.source.PostprocessReformattingAspect.lambda$null$4(PostprocessReformattingAspect.java:245)
at com.intellij.psi.impl.source.PostprocessReformattingAspect.lambda$disablePostprocessFormattingInside$0(PostprocessReformattingAspect.java:113)
at com.intellij.psi.impl.source.PostprocessReformattingAspect.disablePostprocessFormattingInside(PostprocessReformattingAspect.java:121)
at com.intellij.psi.impl.source.PostprocessReformattingAspect.disablePostprocessFormattingInside(PostprocessReformattingAspect.java:112)
at com.intellij.psi.impl.source.PostprocessReformattingAspect.lambda$postponedFormattingImpl$5(PostprocessReformattingAspect.java:245)
at com.intellij.openapi.progress.impl.CoreProgressManager.executeProcessUnderProgress(CoreProgressManager.java:450)
at com.intellij.openapi.progress.impl.ProgressManagerImpl.executeProcessUnderProgress(ProgressManagerImpl.java:54)
at com.intellij.openapi.progress.impl.CoreProgressManager.executeNonCancelableSection(CoreProgressManager.java:198)
at com.intellij.psi.impl.source.PostprocessReformattingAspect.atomic(PostprocessReformattingAspect.java:166)
at com.intellij.psi.impl.source.PostprocessReformattingAspect.postponedFormattingImpl(PostprocessReformattingAspect.java:241)
at com.intellij.psi.impl.source.PostprocessReformattingAspect.doPostponedFormatting(PostprocessReformattingAspect.java:237)
at com.intellij.psi.impl.source.PostprocessReformattingAspect.lambda$doPostponedFormatting$3(PostprocessReformattingAspect.java:220)
at com.intellij.openapi.progress.impl.CoreProgressManager.registerIndicatorAndRun(CoreProgressManager.java:494)
at com.intellij.openapi.progress.impl.CoreProgressManager.executeProcessUnderProgress(CoreProgressManager.java:443)
at com.intellij.openapi.progress.impl.ProgressManagerImpl.executeProcessUnderProgress(ProgressManagerImpl.java:54)
at com.intellij.openapi.progress.impl.CoreProgressManager.executeNonCancelableSection(CoreProgressManager.java:198)
at com.intellij.psi.impl.source.PostprocessReformattingAspect.atomic(PostprocessReformattingAspect.java:166)
at com.intellij.psi.impl.source.PostprocessReformattingAspect.doPostponedFormatting(PostprocessReformattingAspect.java:215)
at com.intellij.psi.impl.source.PostprocessReformattingAspect.decrementPostponedCounter(PostprocessReformattingAspect.java:157)
at com.intellij.psi.impl.source.PostprocessReformattingAspect.access$300(PostprocessReformattingAspect.java:62)
at com.intellij.psi.impl.source.PostprocessReformattingAspect$2.writeActionFinished(PostprocessReformattingAspect.java:103)
at sun.reflect.GeneratedMethodAccessor23.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at com.intellij.util.EventDispatcher.dispatch(EventDispatcher.java:99)
at com.intellij.util.EventDispatcher.access$200(EventDispatcher.java:35)
at com.intellij.util.EventDispatcher$2.invoke(EventDispatcher.java:79)
at com.sun.proxy.$Proxy5.writeActionFinished(Unknown Source)
at com.intellij.openapi.application.impl.ApplicationImpl.fireWriteActionFinished(ApplicationImpl.java:1261)
at com.intellij.openapi.application.impl.ApplicationImpl.endWrite(ApplicationImpl.java:1112)
at com.intellij.openapi.application.impl.ApplicationImpl.access$600(ApplicationImpl.java:93)
at com.intellij.openapi.application.impl.ApplicationImpl$WriteAccessToken.finish(ApplicationImpl.java:1145)
at com.intellij.openapi.command.WriteCommandAction$2.run(WriteCommandAction.java:117)
at com.intellij.openapi.command.impl.CoreCommandProcessor.executeCommand(CoreCommandProcessor.java:129)
at com.intellij.openapi.command.impl.CoreCommandProcessor.executeCommand(CoreCommandProcessor.java:100)
at com.intellij.openapi.command.WriteCommandAction.performWriteCommandAction(WriteCommandAction.java:108)
at com.intellij.openapi.command.WriteCommandAction.execute(WriteCommandAction.java:83)
at com.intellij.openapi.command.WriteCommandAction.runWriteCommandAction(WriteCommandAction.java:187)
at com.intellij.openapi.command.WriteCommandAction.runWriteCommandAction(WriteCommandAction.java:174)
at TextBoxes.changeMethod(TextBoxes.java:171)
at TextBoxes.changeElements(TextBoxes.java:120)
at TextBoxes.actionPerformed(TextBoxes.java:110)
Here is the code that gets the error:
public void changeMethod(PsiJavaFile javaFile, Project project,PsiMethod method){
Runnable modificationRunnable= createMethodRunnable(javaFile,project,method);
WriteCommandAction.runWriteCommandAction(project, modificationRunnable);
}
Any idea on how to fix this error?
Is it the very first exception in the idea.log? (Help | Show log)
If not, please attach the first one. If yes, then it looks like IDEA found itself in an inconsistent state (which shouldn't happen), and it should have reported it with another exception earlier. I'd gladly debug that, but I'd need the full code of the plugin.
How can I send you the code then? I think it will be easier because it seems a deep bug.
You can zip it, upload to some storage and provide a link. You can also upload it to http://uploads.jetbrains.com/
After fixing the problem, my plugin just stopped working both in debug as in production! How can I attach zip's here? It only gives me the possibility to attach images.
Sorry, I've discovered that myself and edited my previous comment.
Here is the link : https://www.dropbox.com/sh/5qpf34nv3qlez30/AAChNrjIe6OTmVzHL_h-nbbIa?dl=0
android-play-billing-master is the project to test the plugin and openIabTranslator is the plugin code.
Tell me if you can reach the same error,
Thank you.
PS: I thing upgrading IntelliJ IDEA to the newest version messed up the plugin, it doesn't find Java classes anymore so it does nothing at all.
Does File | Invalidate Caches and restart help with the "doesn't find Java classes anymore" issue?
I've reproduced the exception. Did you check the log and see another exception before it? Please always use \n in PSI text, IDEA manages line separators itself.
ERROR: Wrong line separators: '\n \r\nserviceI...' at offset 9
java.lang.Throwable
at com.intellij.openapi.diagnostic.Logger.error(Logger.java:132)
at com.intellij.openapi.util.text.StringUtil.assertValidSeparators(StringUtil.java:2679)
at com.intellij.openapi.editor.impl.DocumentImpl.assertValidSeparators(DocumentImpl.java:618)
at com.intellij.openapi.editor.impl.DocumentImpl.replaceString(DocumentImpl.java:544)
at com.intellij.openapi.editor.impl.DocumentImpl.replaceString(DocumentImpl.java:537)
at com.intellij.psi.impl.PsiToDocumentSynchronizer.doCommitTransaction(PsiToDocumentSynchronizer.java:285)
at com.intellij.psi.impl.PsiToDocumentSynchronizer.access$300(PsiToDocumentSynchronizer.java:42)
at com.intellij.psi.impl.PsiToDocumentSynchronizer$6.syncDocument(PsiToDocumentSynchronizer.java:266)
at com.intellij.psi.impl.PsiToDocumentSynchronizer$1.run(PsiToDocumentSynchronizer.java:107)
at com.intellij.psi.impl.PsiToDocumentSynchronizer.performAtomically(PsiToDocumentSynchronizer.java:126)
at com.intellij.psi.impl.PsiToDocumentSynchronizer.doSync(PsiToDocumentSynchronizer.java:104)
at com.intellij.psi.impl.PsiToDocumentSynchronizer.commitTransaction(PsiToDocumentSynchronizer.java:263)
at com.intellij.pom.core.impl.PomModelImpl.commitTransaction(PomModelImpl.java:250)
at com.intellij.pom.core.impl.PomModelImpl.runTransaction(PomModelImpl.java:206)
at com.intellij.psi.impl.source.tree.ChangeUtil.prepareAndRunChangeAction(ChangeUtil.java:167)
at com.intellij.psi.impl.source.tree.CompositeElement.replaceChild(CompositeElement.java:699)
at com.intellij.psi.impl.source.codeStyle.CodeEditUtil.replaceChild(CodeEditUtil.java:204)
at com.intellij.psi.impl.source.tree.CompositeElement.replaceChildInternal(CompositeElement.java:542)
at com.intellij.psi.impl.source.tree.SharedImplUtil.doReplace(SharedImplUtil.java:211)
at com.intellij.psi.impl.source.tree.LazyParseablePsiElement.replace(LazyParseablePsiElement.java:240)
I fixed that and removed the "\r" on the String newSetPackage but the plugin only seems to work one time, if I run it again it doesn't work anymore.. Can you re-run the plugin with the fix and see if IabHelper.java on java.utils is modified ?
BTW it's strongly discouraged to save PSI in long-living fields. AnAction instances are created just once, so your collection fields are never cleared, and likely contain invalid PSI when invoked second time.
Do you recommend resetting the fields at the end?
PS: Still getting the problem while iterating over the java classes, it finds the project folder but
doesn't find anything so the plugin will end with no modifications at all.