Intellij Plugin - Load class object from source project Follow
Hi,
I am trying to develop an Intellij Plugin, which could generate Json Schema out of a Java Class using this awesome library:
https://github.com/FasterXML/jackson-module-jsonSchema
To use this library, the class object is needed, like
JsonSchema schema = schemaGen.generateSchema(SimpleBean.class);
However, I cannot load the class object from my source code in my plugin. My code shows below:
JsonSchema schema = schemaGen.generateSchema(ClassLoader.getSystemClassLoader().load(psiClass.getName()));
Is there anyway to achieve to load class object from source code into plugin?
Please sign in to leave a comment.
Hi,
ClassLoader loads classes from *.class files from directories which are added to its classpath. Classpath of ClassLoader.getSystemClassLoader consists of paths to the IDE JARs, not directories with classes from project opened in the IDE. Also until you build the project where are no *.class files for the source files at all.
So if you want to use this method, you firstly need to build the project, see CompilerManager's javadoc for details. After that you need to create a ClassLoader (e.g. IDEA's com.intellij.util.lang.UrlClassLoader) instance and pass to it URL of the module output directory which contains compiled classes (com.intellij.openapi.roots.CompilerModuleExtension#getCompilerOutputUrl). And then load the class using that class loader (but please note that PsiClass::getName returns short name of the class, you need to use PsiClass::getQualifiedName).
Thank you, Nikolay. It really solved the problem.
A following question would be that I found if I load the *.class using UrlClassLoader, then the @JsonProperty, @Size, and other annotations will not be detected(or I should say "parsed") when the library generating the Json schema.
Do you have any suggestion? Thank you.
You need to add the JARs containing these annotations to classpath as well. You can use OrderEnumerator class to get classpath of your module (something like OrderEnumerator.orderEntries(module).recursively().classes().getUrls()).
Thank you, Nikolay.
I checked that the dependency libraries have been already included in the Plugin project.
In order to test and compare, I create this SimpleBean1.class in my Plugin project, and use the same statement:
it is working fine with the annotations.
However, when I load the SimpleBean2.class(same content with SimpleBean1) from other project into my Plugin project. The output json schema seems never considered/detected the annotations.
I meant that you need to add the JAR containing annotations to the classpath of UrlClassLoader you create.
Just want to clarify,
String simpleBeanClassPath = getSourceClassPath(); // somehow i get the SimpleBean.class path string
ClassLoader classLoader = getClassLoader(); // somehow i create the urlClassLoader of the source code
// Need to add in JAR
Class<?> simpleBeanClass = classLoader.loadClass(simpleBeanClassPath);
JsonNode node = schemaGen.generateSchema(simpleBeanClass);
Do you mean that before I load the SimpleBean.class, I need to add the JAR to my classLoader? Is it in the "// Need to add in JAR" step, or somewhere in the getClassLoader()?
I have tried to use
and then use jars as urls when create the urlClassLoader in the function getClassLoader()
However, i got the same output for json node.
How do you convert String to URL? Look how it's done in our code. Also you can debug the code and try loading annotations classes via the created ClassLoader in debugger to check whether the classpath is configured properly.
Thank you, Nikolay.
The class loading problem has been solved by following the same way in your code.
However, when i try to build the source code using CompileManager, i get java.io.FileNotFoundException: /Applications/IntelliJ IDEA.app/Contents/system/index/indices.enum (No such file or directory)
I checked that it seems there's no system/ directory in /Applications/IntelliJ IDEA.app/Contents
Do you have any suggestion?
I suggest to post the full stacktrace here.
Error:Internal error: (java.lang.RuntimeException) java.io.FileNotFoundException: /Applications/IntelliJ IDEA.app/Contents/system/index/indices.enum (No such file or directory)
java.lang.RuntimeException: java.io.FileNotFoundException: /Applications/IntelliJ IDEA.app/Contents/system/index/indices.enum (No such file or directory)
at com.intellij.util.indexing.ID.writeEnumFile(ID.java:139)
at com.intellij.util.indexing.ID.<clinit>(ID.java:75)
at org.jetbrains.jps.backwardRefs.index.CompilerIndices.<clinit>(CompilerIndices.java:43)
at org.jetbrains.jps.backwardRefs.CompilerBackwardReferenceIndex.<init>(CompilerBackwardReferenceIndex.java:85)
at org.jetbrains.jps.backwardRefs.BackwardReferenceIndexWriter.initialize(BackwardReferenceIndexWriter.java:98)
at org.jetbrains.jps.backwardRefs.BackwardReferenceIndexBuilder.buildStarted(BackwardReferenceIndexBuilder.java:53)
at org.jetbrains.jps.incremental.IncProjectBuilder.runBuild(IncProjectBuilder.java:372)
at org.jetbrains.jps.incremental.IncProjectBuilder.build(IncProjectBuilder.java:192)
at org.jetbrains.jps.cmdline.BuildRunner.runBuild(BuildRunner.java:138)
at org.jetbrains.jps.cmdline.BuildSession.runBuild(BuildSession.java:295)
at org.jetbrains.jps.cmdline.BuildSession.run(BuildSession.java:125)
at org.jetbrains.jps.cmdline.BuildMain$MyMessageHandler.lambda$channelRead0$0(BuildMain.java:236)
at org.jetbrains.jps.service.impl.SharedThreadPoolImpl.lambda$executeOnPooledThread$0(SharedThreadPoolImpl.java:42)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)
Caused by: java.io.FileNotFoundException: /Applications/IntelliJ IDEA.app/Contents/system/index/indices.enum (No such file or directory)
at java.io.FileOutputStream.open0(Native Method)
at java.io.FileOutputStream.open(FileOutputStream.java:270)
at java.io.FileOutputStream.<init>(FileOutputStream.java:213)
at java.io.FileOutputStream.<init>(FileOutputStream.java:162)
at java.io.FileWriter.<init>(FileWriter.java:90)
at com.intellij.util.indexing.ID.writeEnumFile(ID.java:117)
... 17 more
Hello,
what version of IDEA do you use? As I see from the source code you're using 2017.1, so if yes than please update the IDE.
Thank you, Dmitry.
Problem was solved by updating to v15.0.6
Thank you guys so much.
But actual production version of IntelliJ IDEA is 2017.2 and 2017.3 will be available soon. So, I suggest to use at least 2017.2.