47 internal API usages - how enforced is this requirement?

Still waiting for the first human review after sending emails to marketplace but still no answer.

Our internal usages are valid, and simply would not be possible to work as there are almost no other ways to achieve what we’re doing without it.

So the question is, how enforced is this requirement?

Kind of annoying spending months and months on development and getting to this stage at the end.

The methods and usages are all public, its just that they might change in the future, thats what those annotations are for, and the plugin possibly breaking on future Intellij versions, but I feel thats always the case anyway. Plugins are always ending up broken sooner or later and will need to be updated to work in the future.

Still waiting for a reply by email, and I think the team is kind of choked up, but I also wonder, even if they finally manually approve it if this will be the process for every time we upload a new version of the plugin.

Waiting for days on each upload? Just not sustainable.

In my experience, for new plugins it’s enforced unless there’s a clear misattribution of @Internal.

@Internal means “you must not use it because it won’t be approved”.
@Experimental means “use it at your own risk, it may change anytime”.

During your development, you most likely did not run the plugin verifier regularly, which would have shown the usages.

You either need to find a public API replacement (e.g. perhaps NavigationService instead of FileEditorOpenOptions). For some usages like ShutdownTracker or PluginEnabled there’s no replacement I’m aware of, unfortunately.
To find public replacement, clone intellij-community, go to the internal method and try to find callers which are API. Or ask here for help.

They are marker as ApiStatus.Internal, it does not matter they are public. It means they are our implementations details, not for plugins to use.

its just that they might change in the future

No, it means it is not API. Not for plugins to use

So the question is, how enforced is this requirement?

Most likely we will never approve such new usages in a plugin and the version will not be published.

I mean, a lot of things are simply not available as non internal. I don’t see why that should be an issue to use something that clearly has no alternative.

If there was alternatives then there would be no internal. My understanding of internal is that its not to be relied upon to exist, and can change but I don’t think it should be a hard rule.

I would also question the declaration of many such classes or methods with such annotations. If some developer added the annotation, it might linger around for long time, and not even be valid.

The plugin is a really good productivity tool and things like DesktopLayout.getInfo, FileEditorManagerEx.openFile or withRequestFocus(boolean) are methods that do things we need.

WorkingContextManager is something that has no replacement.

I really hope to get an answer soon, and hope it will be reviewed with unbiased eyes.

There are ugly workarounds for some possibly, but I’d prefer if our code did not have to resort to that kind of ugliness.

I am sure there are a lot of approved plugins out there that also rely on internal methods as there simply are no redundant classes lying around to do similar things.

Again, @InternalInternal is mostly, as I understand it, intended to be @NonFinalizedind @InDevelopment @SubjectToChangeNonFinalized or @InDevelopment, @SubjectToChange … so the rule and verifier plugin should flag this kind of things as mostly a warning, not an error or show stopper.

Also, when I ask Claude about these things, it simply tells me:

The 73 internal API usages are the plugin doing what it exists to do, reaching EditorsSplitters, DesktopLayoutandFileEditorManagerImpl. Those cannot go without giving up features.

- 73 internal, 4 experimental, all warnings.

Ship this jar, the verdict is the expected floor and nothing regressed.

Yea, but to be honest the verifier is not really something valid to run pre a first release, and not really known.

Its the final lesson I guess.

Also, many of these things have simply no replacement. If there were, then the internals would simply just swap to using those, and there would be no internal methods.

For me, I understand these as being something as subject to change in future releases, which have almost always been the case that your plugin will eventually need to be updated in the future or stop working due to frequent backwards compatibility issues.

I think that, rather than using internal code, you should explain what your plugin does and which features currently use internal code. We should be able to help you migrate to standard APIs, or determine whether certain features are not legitimate.

And, I insist on this: don’t trust Claude :wink:

@Internal is defined here: java-annotations/src/jvmMain/java/org/jetbrains/annotations/ApiStatus.java at master · JetBrains/java-annotations · GitHub

Even if you or Claude understand its meaning differently, JetBrains’ opinion and definition is what counts…
You could

  • find replacements, as I mentioned earlier
  • copy code from intellij-community if it’s not using @Internal code again (taking care of the license, of course)
  • drop the feature from your plugin

If you explain what you would like to do, then you’ll probably get better feedback or recommendations.

Yes, it does not mean that we allow it, it is our implementation details, not for plugins to use. Consider them as internal modifier in Kotlin, you may not compile with that.

On constructive note, for some of your usages there are alternatives:

  • FileEditorOpenOptions – find methods FileEditorManagerEx#openFile receiving FileEditorOpenRequest, which is public and experimental
  • StartupUtil.isDarkTheme - !JBColor.isBright()
  • com.intellij.ui.render.RenderingUtil#CUSTOM_SELECTION_BACKGROUND – please submit an issue to us as documentation suggests Internal API Migration | IntelliJ Platform Plugin SDK

For enabling/disabling plugin there is no any API and not planned (at least directly), we do not allow plugins manage other plugins. Same as ShutDownTracker, as it is too dangerous and low level.

As a perfectionist, dropping features is not really an option… its quite a feature riuch plugin so i wouldn’t even know where to start.

"Such element may be renamed, changed or removed in future versions."

This is the take away for me. Thats why its marked internal.

Although:

``<p>If a method is marked with this annotation, overriding methods are not considered internal.</p>```

Maybe leaves some door open … if one is to take that literally…

If you explain what you would like to do, then you’ll probably get better feedback or recommendations.

Its a big plugin again .. with quite a large code base at this point … so its not about something thats easily altered … but I will try to find a way.

Thanks, thats some ugly hacks though.

StartupUtil.isDarkTheme - !JBColor.isBright()

I have 47 issues, I simply can’t be filing tickets one by one to change them. Will take months to years. I would have liked to be able to start offering the plugin soon.

I wonder if its distributed as free version also runs into these kinds of hurdles. Or is it just for paid plugins? Cause back in the days, I did not encounter these kinds of verifiers when uploading a plugin.

Why is ShutDownTracker dangerous? Its simply allowing you to be notified when it shuts down.

Again, these kinds of annotations are good to have, such as @Deprecated, or @SoonToBeDeprcated, or @MightChangeInTheFuture … but to enforce them or mark large parts of the code as @Internal and refusing to allow their use kind of defeats the purpose of a platform which we are supposed to be able to extend if users might feel something is missing.

I will try to get around some of thesee, but to be able to pull off 47 is asking for too much. I might have to resort to some tricks, and this will take so much effort because some coder decides to mark something internal cause they wanted to make the API or code modifiable.

I feel as it should be as a plugin developers own risk if you are using something that you’ve been told might change in the future. The code won’t even compile likely if something is renamed or moved, or deleted.

As in its internal, i feel a lot of it is not really that internal.

Some simply just annotated with that in the end just takes more options or parameters and the non internal version is just a very limited subset.

Needless to say, the annotation seems to be saying overriding might be an option to bypass, but also not sure if that will actually work, especially for static access classes and methods.

Reflection might also work, but I feel that will just become untenable and beats the purpose.

Thank you, I hope you just understand its kind of frustrating having spent so much time to get into this kind of delay at this point.

I know you are guiding me, but I am also hoping Jetbrains can after testing of the plugin give a pass on this kind usage. It did not sound like it was impossible.

From what I see, only those things mentioned by me have way forward. Any others don’t, so in the current form it cannot be published to users.

I mention it explicitly. Any attempt to circumvent our API usage policies is a risk of permanent ban for a plugin in the Marketplace.

I’m pretty sure that you won’t get approval with the existing usages of internal API.

That’s @Experimental, not the @Internal annotation. Reality doesn’t just change because you think differently :wink:

As far as I understand, this is for overridden method which are part of the SDK. You can’t override internal API without a violation, but you can use overridden internal API without a violation.

Good luck!

(I won’t reply to this issue again, it’s all said)

This is not what we are saying. We say - we do not provide that to plugins, no such thing for them, implementation detail.

By the way it says that its compatible overall, so I am not really sure.

I also had more serious warnings before, and these seem to be listed as less serious issues.

A bit confusing … still awaiting some kind of official response.

“As far as I understand, this is for overridden method which are part of the SDK. You can’t override internal API without a violation, but you can use overridden internal API without a violation.”

Thats your understanding, but it does not really say that though.

Maybe it is like you said though. I will soon review and figure out what I can drop to get it through but it will likely be a bit of an effort.

I think the majority of plugin developers do not use the internal APIs. From what I understand, the documentation and the warnings displayed in the IDE are sufficient, but I may be missing something. In other words, what seems clear to me may not be clear to you, and that is perfectly understandable.
So, if you think the documentation (or anything else) could be improved to prevent developers from using the internal APIs, your contribution would be most welcome.

It could refuse to build the plugin in the editor, or refuse to launch it in the sandbox, or install it manually yourself, not first time when uploaded to marketplace.

If its an error, then the plugin dev environment should say its an error. Currently its highlighted as a @Deprecated might and thats not an error, its a warning or informative. Gradle build could show it as an error and refuse to launch it.

That way no one has to spend months building and running it locally to hit a wall when uploading it later.

Also, I had uploaded two different versions.

First say compatibility problems.

But since fixing the first 2 ( which were not even a correct call ), I am getting compatible:

The UI might be rendering it in red, but the verifier is not saying this is incompatible, but actually compatible.

Furthermore, in the first version, yesterday, it was saying Critical. Now something changed to make it only Problems … maybe someone has been reading my emails and patching.

Thanks though for giving me some energy to drive this forward.

I have been able to reduce it now to 20 internal issues, and working on the remains. I might have to drop some functionality or presentation thats not important.

I think i will get there, but its a 3 days now that I have “wasted” which could have been avoided I guess.

You should have tested your plugin against the plugin verifier sooner. Again, I’m not sure whether the documentation could be improved, but please feel free to contribute to it. Your experience could be useful to other plugin developers.

So I will also leave this thread. You should not insist like that, it leads to nothing.