How do I create a Maven project library from within an IntelliJ plugin?
I’m attempting to copy a global maven library to the project level, using the IntelliJ plug-in API.
I came up with a very ugly way to find the Maven coordinates from the global library:
if( sourceLib instanceof LibraryBridgeImpl sourceLibBridge && sourceLibBridge.getProperties().getClass().getName().equals( "org.jetbrains.idea.maven.utils.library.RepositoryLibraryProperties" ) ) {
final String mavenCoordinates;
try {
mavenCoordinates = sourceLibBridge.getProperties().getClass().getMethod( "getRepositoryLibraryDescriptor" ).invoke( sourceLibBridge.getProperties() ).toString();
} catch( Exception e ) {
throw new RuntimeException( e );
}
}
I had to use reflection because I get a ClassNotFoundException if I try to use the RepositoryLiibraryProperties directly. If there is a better way to get this, please let me know.
This gives me the Maven coordinates, but I don’t see how to use them to create a Maven project library.
I tried following the steps at “Creating a Library” at https://plugins.jetbrains.com/docs/intellij/library.html, but that creates a regular library, not a Maven library.
Please sign in to leave a comment.
Hi,
Please describe your use case. What do you mean by global Maven library and copying it to the project level? What is the context? Are you implementing some action or something else?
Using reflection is a no-go. Please clarify your case.
In the IDE interface, you can go to project structure → global libraries, right click a library, then select the option to copy that to project libraries. I’m trying to replicate that same behavior from an IntelliJ plugin that I am developing.
This works if I’m trying to copy a “regular” library, but if the global library is based on a repo from maven coordinates, the resulting copied library does not have the blue ‘m’ icon, and does not have a link to the external repository.
In this screenshot, the result of following the IntelliJ documentation for creating a library gives me a library like the ‘slf4j’ one below (note the icon, and lack of Maven coordinates). The desired result is the ‘IntellijAnnotations’ library, with the blue Maven icon and the link to the external repository.
Answering your direct question:
see com.intellij.jarRepository.JarRepositoryManager#chooseLibraryAndDownload implementation
https://github.com/JetBrains/intellij-community/blob/master/java/idea-ui/src/com/intellij/jarRepository/JarRepositoryManager.java
But, it looks like XY-problem.
In real world this creates a JPS-managed library, I wouldn't recommend to do this in your plugin. JPS is a native IDEA project, and projects in real-world do not use (and should not) use it as golden-source of project structure definition, they use maven/gradle/bazel/ant, if we are talking about java world.
do this if and only if you create a dev-plugin for some specific project in your organization. If you do some general purpose plugin consider https://github.com/JetBrains/intellij-community/blob/master/platform/external-system-api/src/com/intellij/openapi/externalSystem/service/project/manage/ProjectDataService.java for gradle/sbt based projects
and/or https://github.com/JetBrains/intellij-community/blob/master/plugins/maven/src/main/java/org/jetbrains/idea/maven/importing/MavenConfigurators.kt for maven
We use the native IntelliJ build system for our projects, which I prefer over Gradle / Maven. I'm not sure why you say you should not use this as the golden-source of project structure definition. If you feel like expanding on that or pointing to a link in the docs discussing that, that would be great, if not, that's fine, your answer was very helpful in solving my problem.
Here's the solution I came up with. This is based on code from com.intellij.openapi.roots.ui.configuration.classpath.ChangeLibraryLevelActionBase.doCopy(LibraryEx library)
private void copyGlobalLibraryToProject( Project project, String libraryName ) {
LibraryTable globalTable = LibraryTablesRegistrar.getInstance().getLibraryTable();
final LibraryEx sourceLibrary = Objects.requireNonNull( (LibraryEx )globalTable.getLibraryByName( libraryName ) );
LibraryTable libraryTable = LibraryTablesRegistrar.getInstance().getLibraryTable(project);
final LibraryTable.ModifiableModel modifiableModel = libraryTable.getModifiableModel();
final Set<File> fileToCopy = new LinkedHashSet<>();
final Map<String, String> copiedFiles = new HashMap<>();
for (OrderRootType type : OrderRootType.getAllTypes()) {
for (VirtualFile root : sourceLibrary.getFiles(type)) {
if (root.isInLocalFileSystem() || root.getFileSystem() instanceof ArchiveFileSystem ) {
fileToCopy.add( VfsUtilCore.virtualToIoFile( VfsUtil.getLocalFile(root)));
}
}
}
fileToCopy.forEach( from -> copiedFiles.put( FileUtil.toSystemIndependentName(from.getAbsolutePath()), FileUtil.toSystemIndependentName(from.getAbsolutePath()) ) );
final Library copied = modifiableModel.createLibrary( libraryName, sourceLibrary.getKind());
final LibraryEx.ModifiableModelEx model = (LibraryEx.ModifiableModelEx)copied.getModifiableModel();
LibraryEditingUtil.copyLibrary(sourceLibrary, copiedFiles, model);
WriteAction.run(() -> {
model.commit();
modifiableModel.commit();
});
}