2
头图

The Language Support for Java 1.1.0 version contains an important update: Now when the plugin imports a new Java project, the project metadata file (.project, .classpath, settings, etc.) will no longer be generated in project path . This problem has been recorded for more than three years since 2018. This article aims to record and share our process of solving this problem and the final solution.

The "Sword of Damocles" hanging overhead

With the gradual enrichment of VS Code Java's functions, the number of users is also steadily increasing. However, due to the problem that the Java plug-in will generate metadata files in the project directory when importing the project, we have received a lot of 1-star bad reviews. It is foreseeable that as the user base increases, the number of negative reviews caused by this problem will also increase. This is like a " Damocles sword" hanging over our heads. If it is not resolved in time, the problem may break out at any time.

In fact, this is not that our product team does not want to completely fix this problem. The root cause needs to start from the architecture of the Java Language Service:

1510adb95d5faa855f48633cc94f6294.jpg
JDT Java Language Server architecture diagram

The official project name of the Java language service used behind the VS Code Java project is Eclipse JDT Language Server™, which was jointly developed Red Hat As you can see in the project architecture diagram above, we reused some Eclipse modules in the implementation, and these automatically generated metadata files are also generated by some of the upstream modules. A related discussion thread can be found in the Eclipse discussion area. The creation time of this post can even be traced back to 2004. Because at the time of implementation, the metadata file path has been hard-coded as constants in the code, these constants has been the various modules of Eclipse plug-ins and even quoted, in a sense this problem long years down Shanghai has become a "historical burden".

Considering that changing the behavior of upstream modules contains too many unknowns and uncertainties, in the past we tried to provide users with some workarounds, such as hiding these metadata files in the file browser of VS Code and guiding users to them Add to .gitignore. But judging from user feedback, these methods did not satisfy users. illness " that has plagued us and users for more than three years, we decided to try again in the second half of this year, hoping to "curse" it.

Solution 1. Use Symbolic Link (Failed)

The first method we thought of was to use Symbolic Link . When importing a project, you can link the imported project to a place invisible to the user through Symbolic Link, so that the metadata file is generated under the linked path. But soon this scheme ran into problems-creating Symbolic Link under certain operating systems requires specific permissions, otherwise FileSystemException will be thrown, which is obviously not the effect we want, so this scheme was immediately rejected.

Plan two, use Eclipse Linked Resources (abandoned)

Similar to the idea of Symbolic Link, we can also choose to use Eclipse Linked Resources:

Linked Resources: Linked resources are files and folders that are stored in locations in the file system outside of the project's location.

The above is an official definition of Linked Resources, which can be used as part of the project, but it is allowed to be stored in other locations outside the project path. In VS Code Java, for the Unmanaged Folder (project without a build system), these metadata files are hidden through the Linked Resources mechanism. Its implementation principle is shown in the following figure:

488365ba19ac6197bd957b3615c0741f.jpg
Unmanaged Folder implementation principle

You can see that the actual path of the project is placed in the Language Server workspace storage. The user usually does not know this path. At the same time, we define the target path of Linked Resources in the .project file, which is the folder opened by the user in VS Code Location, as a part of the project, it will participate in the construction process like other projects, and its development experience is similar.

The same principle can be applied to the import process of Maven project and Gradle project to solve this problem. Therefore, we conducted some experiments on the M2E module. The M2E module is responsible for importing the Maven project in the Java Language Service. By modifying the relevant code in the module and using the Linked Resources mechanism, the metadata file can be generated outside the project path.

The final experimental results are feasible, but the shortcomings of this scheme are also very obvious:

  • large changes. : The code that needs to be changed is scattered in different files of the entire module (about a dozen places). At the same time, because of the large code size, there is no way to determine whether these changes are complete in a short time.
  • opaque to downstream modules. : Because there is an extra layer of Linked Folder, this will make the Java project view display the project structure, an extra layer representing the directory structure of the Linked Folder. In the implementation of the Java project view , some additional control logic needs to be added to make the display of the project structure the same as the normal project.
  • The feasibility of : The support modules for Maven and Gradle build systems, M2E and Buildship, are both upstream projects. It is unknown whether this concept can be adopted or not.
  • has poor scalability. : If you want to support a new build system, you need to implement similar logic again.

Taking into account the above reasons, the team decided to temporarily abandon the Eclipse Linked Resources solution after discussion and continue to find a better solution.

found " silver bullet "

There is another reason for abandoning the second set of solutions: Twenty years since Eclipse was released, while ensuring stable operation, it can continuously add new functions and provide excellent expansion capabilities. Behind this, there must be an excellent architecture. Design and scalability. Intuitively, we think there should be more elegant solutions.

Therefore, this time we directly analyzed the underlying file system of Eclipse and finally found a "silver bullet" to solve the problem: File System Provider and FileStore (Note: Although in the Software Engineering , the consensus is that There is no silver bullet, but for this particular problem, we did find a more "KitKat" solution).

Eclipse Workspace structure and FileStore

tree structure for the entire workspace during operation. The nodes of the tree represent files or directories in the file system, and some important information about the files, such as modification time, are also saved.

The bottom layer of Eclipse associates these nodes with files in the file system through the FileStore class. The FileStore class has another important feature: if the mapped object is a single file, then FileStore will also be responsible for providing the input and output streams of this file.

This feature brings a very important idea for the solution of the problem: as long as the input and output streams of the metadata file can be redirected to a location outside the project directory, the problem may be solved. With this assumption, we found another key clue: File System Provider.

Solution Three, File System Provider

File System Provider is an extension point open to the Eclipse platform. It allows developers to implement an Eclipse file system interface (org.eclipse.core.filesystem.IFileSystem) and register it to the extension point to handle specific URIs. Scheme file request.

So we started from the extension point of File System Provider, inherited and overridden the file system whose URI scheme is file by Eclipse's default processing, by overriding some of these methods, let the file system redirect the file path when processing metadata files Read and write to a place outside the project path. Compared with the second scheme, the advantages of this set of schemes are:

  • completely transparent to other modules , and can work normally without modification, which also means better .
  • code size of is very small. The final implementation, including JavaDoc and comments, is only about 300 lines in total.

Of course, this solution is not perfect, because it requires other modules to read and write metadata files through the API provided by Eclipse. We found upstream Buildship in the implementation process to read and write when dealing with metadata files directly through the JDK file the I / O API , for which we submitted a change request the migration-related operations Go to the Eclipse API.

Summary

After weighing the pros and cons, we finally chose the third set of solutions and solved this problem that has plagued VS Code Java users for more than three years. Although the final realization is not complicated, the process of searching for answers is very dramatic.

Finally, special thanks to Eclipse Platform project members Mickael Istria and Alexander Fedorov. In the process of problem discussion, they gave very useful suggestions, which played a very crucial role in solving the problem.

feedback and suggestions:

Please actively use our products! Your feedback and suggestions are very important to us and will help us do better. There are several ways to leave us feedback

Resource:


Welcome to follow the Microsoft China MSDN subscription account for more latest releases!
image.png


微软技术栈
423 声望996 粉丝

微软技术生态官方平台。予力众生,成就不凡!微软致力于用技术改变世界,助力企业实现数字化转型。