Why does the PsiField.getAnnotation() behave differently in different test environments.

Hello,

I want to get the annotation on a field in jvm language.

I used UAST API.

PsiElement elementAt = psiFile.findElementAt(editor.getCaretModel().getOffset());
// ADAPTS to all JVM platform languages
UClass uClass = UastUtils.findContaining(elementAt, UClass.class);
PsiClass psiClass = uClass.getJavaPsi();
PsiField psiField = psiClass.getFields()[0];
PsiAnnotation psiAnnotation = psiField.getAnnotation(com.fasterxml.jackson.annotation.JsonProperty.class.getName());

I resolve target class:

java

import com.fasterxml.jackson.annotation.JsonProperty;

public class User {
@JsonProperty("name")
private String username;
}

kotlin

import com.fasterxml.jackson.annotation.JsonProperty

class User {
@JsonProperty("name")
private val username: String? = null
}

 

The first case:
Run gradle bulid "runIde".

The psiAnnotation can get object on the java.

The psiAnnotation can get object on the kotlin.

The second case:
Run test case.

The psiAnnotation can get object on the java.

The psiAnnotation get null on the kotlin.

 

0
15 comments

Hi Wang,

I assume that you include the Kotlin plugin in your Gradle Build script. I mean plugins section: https://github.com/JetBrains/gradle-intellij-plugin#configuration

How do you run your test case? Is it delegated to Gradle or run with the default test runner (see https://www.jetbrains.com/help/idea/work-with-tests-in-gradle.html)? What happens when you run Gradle "test" task?

0

1. I'm sure I include the Kotlin plugin in my Gradle Build script.

https://github.com/organics2016/pojo2json/blob/master/build.gradle.kts 

intellij {
version.set("2020.3")
updateSinceUntilBuild.set(false)
// https://github.com/JetBrains/gradle-intellij-plugin/issues/38
plugins.set(listOf("java", "Kotlin", "org.intellij.scala:2020.3.21"))
}

2. It is correct only when run Gradle "runIde"

Whether it is run Gradle "test" or run default test runner the psiAnnotation get null on the kotlin.

 

0

Hi Wang,

It may be the test context misconfiguration if it works for you in the running IDE.

Could you please provide us with the test project that you use for "runIde"?

0

Hi Karol,

Thank you for your attention to this issue.

This my project repository.

https://github.com/organics2016/pojo2json 

This is my test class, It has a method called "testThis()" . These two methods test Java and Kotlin class files.

You can run test runner.

src/test/java/ink/organics/pojo2json/test/JavaTestCase.java

src/test/java/ink/organics/pojo2json/test/KotlinTestCase.java

If you want run Gradle "runIde" ,After the IDE UI starts, you can test these two files.

Just right click in the file and select "POJO To JSON"

src/test/java/testdata/java/JsonPropertyTestPOJO.java

src/test/java/testdata/kotlin/JsonPropertyTestPOJO.kt

These four results failed only in KotlinTestCase.testThis().

0

Hi Wang,

I've seen your plugin project repository, but what I need now is the test project you use for the runIde task. Could you please provide it in a temporal GitHub repository or just a ZIP file? I want to be sure all dependencies are exactly the same as in your case.

So I need to check both contexts: test and running IDE and for running IDE I need your test project.

0

This is my test repository and test files path

https://github.com/organics2016/test

 

src/main/java/ink/organics/test/testdata/java/JsonPropertyTestPOJO.java

src/test/java/testdata/kotlin/JsonPropertyTestPOJO.kt

0

What progress has been made on this issue?

If it's an environment problem, I can't find the difference.

0

Your tests reference e.g. com.fasterxml.jackson.annotation.JsonProperty from 3rd party library (and also fastjson), but it is not correctly setup in ink.organics.pojo2json.test.TestCase#getProjectDescriptor. It is currently resolved from the JDK configured in this method, but this is not correct approach (see below). To add libraries into test's project classpath, use https://plugins.jetbrains.com/docs/intellij/testing-faq.html#jvm-how-to-add-maven-dependencies (see de.plushnikov.intellij.plugin.LombokTestUtil in IntelliJ Community sources as reference).

Whether or not this resolves the Kotlin specific problem is not clear, but it must be fixed first. Will update with more information.

Please review these items as well:

- do not use com.intellij.openapi.projectRoots.impl.JavaAwareProjectJdkTableImpl#getInternalJdk in ink.organics.pojo2json.test.TestCase#getProjectDescriptor, you should point to (mock) JDK instead as described here: https://plugins.jetbrains.com/docs/intellij/tests-prerequisites.html#set-the-run-configuration-parameters

- do not specify optional plugin descriptors in plugin.xml if they contain no specific content

- the plugin will _require_ Java plugin to be present in order to work, so it must be listed accordingly in plugin.xml <depends>

- ink.organics.pojo2json.POJO2JsonAction#update must not use hardcoded language IDs or keywords of languages. Use UAST tree and org.jetbrains.uast.UastLanguagePlugin#isFileSupported to check applicability. https://plugins.jetbrains.com/docs/intellij/uast.html

- similar in ink.organics.pojo2json.POJO2JsonAction#parseFieldValueType, do not assume `<` in any of supported UAST languages or any of its syntax, same problem in ink.organics.pojo2json.POJO2JsonPsiUtils methods

- use "<caret>" in testdata to position and locate current element instead of hardcoded way in ink.organics.pojo2json.test.TestCase#testAction, see https://plugins.jetbrains.com/docs/intellij/test-project-and-testdata-directories.html#special-markup

- don't throw exception from ink.organics.pojo2json.POJO2JsonAction#actionPerformed, but instead disable the action via update() if it's not possible to invoke it in the first place with meaningful results

0

Thank you for your answer.

I find demo https://github.com/JetBrains/intellij-community/blob/master/plugins/lombok/src/test/java/de/plushnikov/intellij/plugin/LombokTestUtil.java 

So, My code

@Override
protected LightProjectDescriptor getProjectDescriptor() {
return new DefaultLightProjectDescriptor() {
@Override
public Sdk getSdk() {
return IdeaTestUtil.getMockJdk18();
}

@Override
public void configureModule(@NotNull Module module, @NotNull ModifiableRootModel model, @NotNull ContentEntry contentEntry) {
MavenDependencyUtil.addFromMaven(model, "com.alibaba:fastjson:1.2.76");
model.getModuleExtension(LanguageLevelModuleExtension.class).setLanguageLevel(LanguageLevel.JDK_1_8);
}
};
}

throw Exception:

java.lang.RuntimeException: java.io.IOException: Cannot find IntelliJ IDEA project files at C:\Users\organics\.gradle\caches\modules-2\files-2.1\com.jetbrains.intellij.idea\ideaIC\2020.3\22cef0fc611e4b9642a48bc955b2b7aacb13bd4d\ideaIC-2020.3
at com.intellij.testFramework.LightPlatformTestCase.initProject(LightPlatformTestCase.java:216)
at com.intellij.testFramework.LightPlatformTestCase.lambda$doSetup$2(LightPlatformTestCase.java:273)
at com.intellij.openapi.application.impl.ApplicationImpl.invokeAndWait(ApplicationImpl.java:463)
at com.intellij.openapi.application.impl.ApplicationImpl.invokeAndWait(ApplicationImpl.java:481)
at com.intellij.testFramework.LightPlatformTestCase.doSetup(LightPlatformTestCase.java:266)
at com.intellij.testFramework.fixtures.impl.LightIdeaTestFixtureImpl.setUp(LightIdeaTestFixtureImpl.java:37)
at com.intellij.testFramework.fixtures.impl.CodeInsightTestFixtureImpl.lambda$setUp$28(CodeInsightTestFixtureImpl.java:1200)
at com.intellij.testFramework.EdtTestUtil.runInEdtAndWait(EdtTestUtil.java:33)
at com.intellij.testFramework.fixtures.impl.CodeInsightTestFixtureImpl.setUp(CodeInsightTestFixtureImpl.java:1199)
at com.intellij.testFramework.fixtures.BasePlatformTestCase.setUp(BasePlatformTestCase.java:51)
at ink.organics.pojo2json.test.TestCase.setUp(TestCase.java:60)
at com.intellij.testFramework.UsefulTestCase.invokeSetUp(UsefulTestCase.java:428)
at com.intellij.testFramework.UsefulTestCase.defaultRunBare(UsefulTestCase.java:420)
at com.intellij.testFramework.UsefulTestCase.lambda$runBare$11(UsefulTestCase.java:481)
at com.intellij.testFramework.EdtTestUtil.lambda$runInEdtAndWait$1(EdtTestUtil.java:40)
at java.desktop/java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:303)
at java.desktop/java.awt.EventQueue.dispatchEventImpl(EventQueue.java:770)
at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:721)
at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:715)
at java.base/java.security.AccessController.doPrivileged(Native Method)
at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:85)
at java.desktop/java.awt.EventQueue.dispatchEvent(EventQueue.java:740)
at com.intellij.ide.IdeEventQueue.dispatchEvent(IdeEventQueue.java:421)
at java.desktop/java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:203)
at java.desktop/java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:124)
at java.desktop/java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:113)
at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:109)
at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)
at java.desktop/java.awt.EventDispatchThread.run(EventDispatchThread.java:90)
Caused by: java.io.IOException: Cannot find IntelliJ IDEA project files at C:\Users\organics\.gradle\caches\modules-2\files-2.1\com.jetbrains.intellij.idea\ideaIC\2020.3\22cef0fc611e4b9642a48bc955b2b7aacb13bd4d\ideaIC-2020.3
at org.jetbrains.jps.model.serialization.JpsProjectLoader.loadProject(JpsProjectLoader.java:101)
at org.jetbrains.jps.model.serialization.JpsProjectLoader.loadProject(JpsProjectLoader.java:83)
at org.jetbrains.jps.model.serialization.impl.JpsSerializationManagerImpl.loadProject(JpsSerializationManagerImpl.java:32)
at com.intellij.project.IntelliJProjectConfiguration$Companion.loadIntelliJProject(IntelliJProjectConfiguration.kt:90)
at com.intellij.project.IntelliJProjectConfiguration.<init>(IntelliJProjectConfiguration.kt:34)
at com.intellij.project.IntelliJProjectConfiguration$Companion$instance$2.invoke(IntelliJProjectConfiguration.kt:48)
at com.intellij.project.IntelliJProjectConfiguration$Companion$instance$2.invoke(IntelliJProjectConfiguration.kt:47)
at kotlin.SynchronizedLazyImpl.getValue(LazyJVM.kt:74)
at com.intellij.project.IntelliJProjectConfiguration$Companion.getInstance(IntelliJProjectConfiguration.kt)
at com.intellij.project.IntelliJProjectConfiguration$Companion.getRemoteRepositoryDescriptions(IntelliJProjectConfiguration.kt:52)
at com.intellij.project.IntelliJProjectConfiguration.getRemoteRepositoryDescriptions(IntelliJProjectConfiguration.kt)
at com.intellij.testFramework.fixtures.MavenDependencyUtil.getRemoteRepositoryDescriptions(MavenDependencyUtil.java:79)
at com.intellij.testFramework.fixtures.MavenDependencyUtil.addFromMaven(MavenDependencyUtil.java:52)
at com.intellij.testFramework.fixtures.MavenDependencyUtil.addFromMaven(MavenDependencyUtil.java:39)
at com.intellij.testFramework.fixtures.MavenDependencyUtil.addFromMaven(MavenDependencyUtil.java:28)
at ink.organics.pojo2json.test.TestCase$1.configureModule(TestCase.java:77)
at com.intellij.testFramework.LightProjectDescriptor.lambda$createContentEntry$3(LightProjectDescriptor.java:150)
at com.intellij.openapi.roots.ModuleRootModificationUtil.lambda$updateModel$8(ModuleRootModificationUtil.java:126)
at com.intellij.openapi.roots.ModuleRootModificationUtil.modifyModel(ModuleRootModificationUtil.java:134)
at com.intellij.openapi.roots.ModuleRootModificationUtil.updateModel(ModuleRootModificationUtil.java:125)
at com.intellij.testFramework.LightProjectDescriptor.createContentEntry(LightProjectDescriptor.java:139)
at com.intellij.testFramework.LightProjectDescriptor.lambda$setUpProject$0(LightProjectDescriptor.java:45)
at com.intellij.openapi.application.WriteAction.run(WriteAction.java:102)
at com.intellij.testFramework.LightProjectDescriptor.setUpProject(LightProjectDescriptor.java:39)
at com.intellij.testFramework.LightPlatformTestCase.initProject(LightPlatformTestCase.java:195)
... 28 more

I know this library("com.alibaba:fastjson:1.2.76") does not exist in the IntelliJ IDEA project files.  But how should I add it?

0

Hi, Yann

I solved most of the problems you raised. Thank you for your work to make my project more stable.

Unfortunately, using mock JDK still can not get the expected results. 

The mock JDK seems to process strings as objects when serializing.

And the MavenDependencyUtil#addFromMaven still can't working.

 

 

0

Use overload to specify additional Maven repositories com.intellij.testFramework.fixtures.MavenDependencyUtil#addFromMaven(com.intellij.openapi.roots.ModifiableRootModel, java.lang.String, boolean, com.intellij.openapi.roots.DependencyScope, java.util.List<com.intellij.jarRepository.RemoteRepositoryDescription>) if the library cannot be resolved from builtins.

 

Regarding mock JDK, you must follow instructions from https://plugins.jetbrains.com/docs/intellij/tests-prerequisites.html#set-the-run-configuration-parameters exactly.

0

Thank you.

The 3rd party library problem has been solved. Now it can work in different language environments.

But the com.intellij.psi.util.PsiUtil#resolveClassInClassTypeOnly(type) results of Mock JDK and Local JDK are different.

 

0

I'm sure the "idea.home.path" configuration is effective.

Because 3rd party library take effect only after I configure this prop.

0

Please debug com.intellij.openapi.projectRoots.impl.MockSdk#getHomeDirectory to return proper file

0

Thanks very much for your help. You solved all my problems.

I thought this directory (java/mockJDK-$JAVA_VERSION$) was built by IDEA SDK itself, just like Maven library.

Anyway, I misunderstood the document.

0

Please sign in to leave a comment.