How to adapt to old version of API and new version of API? Method already removed from API.

Answered

I'm using 

LanguageAnnotators.INSTANCE.addExplicitExtension

 

But it seems that this method is added from 2018.02.07. And removed registerExplicitExtension.

 

How can I avoid this problem without make two different plugins?

 

What I want to do is like this,

if(version > 2018.02.07) { // or if(LanguageAnnotators.INSTANCE.respond?(:addExplicitExtension)) { // respond? is Ruby method though
LanguageAnnotators.INSTANCE.addExplicitExtension
} else {
LanguageAnnotators.INSTANCE.registerExplicitExtension
}

 

But for Java, this will be Syntax Error, because one version has only either method.

 

Is there any way to solve this?

 

11 comments
Comment actions Permalink

Could you please clarify where method registerExplicitExtension is found and what IDE version you refer to? com.intellij.openapi.util.KeyedExtensionCollector#addExplicitExtension has been there forever AFAIU.

0
Comment actions Permalink

Thank you for your reply.

Actually I don't know how to see downgrade version of APIs.

 

So, I checked these posts.

https://intellij-support.jetbrains.com/hc/en-us/community/posts/206126569-Annotator-for-all-files-?page=1#community_comment_206159025

https://intellij-support.jetbrains.com/hc/en-us/community/posts/115000709564-Annotator-for-all-languages

 

And compatible problem is this.

 

U-171.4694.73 (2017.1.6) Found 1 compatibility problem

 

0
Comment actions Permalink

Actually, I set build.gradle to this version of IntelliJ (2017.1.6). I still found this method in there.

I don't understand why this compatibility problem occurred...

0
Comment actions Permalink

Indeed, the verification warning isn't clear. It may be a false-positive of the static analysis.

Could you provide a link to your plugin in https://plugins.jetbrains.com/ or at least the name of it, so I could recheck it locally.

0
Comment actions Permalink

Thanks! This case has turned to be a bit trickier than it seems. It is a correct warning, and your plugin will not work with 181.* or lower due to NoSuchMethodError.

Explanation: 

This overriding was done in 182 in class LanguageExtension:

@Override public void addExplicitExtension(@NotNull Language key, @NotNull T t)

In bytecode it has the following signature 

public addExplicitExtension(Lcom/intellij/lang/Language;Ljava/lang/Object;)V

note Language as the first parameter. This is due to generic parameter KeyT of class KeyedExtensionCollector.

Before 182 this signature in bytecode didn't exist.

Once you compile your plugin against 182 it becomes dependent upon existence of this signature in bytecode. 

In 181.* and before the method was not overridden and was simply inherited from KeyedExtensionCollector with this signature

public addExplicitExtension(Ljava/lang/Object;Ljava/lang/Object;)V

 Thus, when you run the plugin in 181 you will encounter

java.lang.NoSuchMethodError: addExplicitExtension(Lcom/intellij/lang/Language;Ljava/lang/Object;)V

 

I hope it clarifies the warning.

For more info about bytecode compatibility you may refer to https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-6.html#jvms-6.5.invokevirtual.

0
Comment actions Permalink

Thank you for reply.
I still have two things I don’t understand.

1. Why any exception happened when I set 2017.1.6 to IntelliJ version in build.gradle?
2. How should I change my code?? Ned o use invokevirtual??

0
Comment actions Permalink

I think the 1 is because if I set 2017.1.6 in build.gradle, I build codes with this version, so the byte codes are collect.
But when published it only has one version of byte codes?
I think I understand.

And if use invoke virtual it search method at runtime so it will be fine?

0
Comment actions Permalink

Once you set version to 2017.1.6, the java compiler references the older signature (Object;Object)V because it doesn't even know about (Language;Object)V that appears later in 2018.*.

And this is a solution: just compile your plugin with 2017.1.6 (set this version in build.gradle).  You don't have to change the source code.

 

0
Comment actions Permalink

Thank you!
I’ll try it!

0
Comment actions Permalink

Exactly! When your plugin is run with 2018.3 (with newer signature added), the plugin will still work because in bytecode of 2018.3 there are two signatures at the same time (Object;Object)V and (Language;Object)V, of which your plugin refers only the former.

0

Please sign in to leave a comment.