Dígale adiós a los archivos “.project” en Language Support para Java ™ 1.1.0

La reciente versión 1.1.0 de Language Support para Java  contiene una actualización importante: ahora, cuando la extensión importe un nuevo proyecto Java, los archivos de metadatos del proyecto (.project, .classpath, configuraciones, etc.) ya no se generarán en el proyecto. ruta por defecto. Este problema se informó hace más de tres años y ha estado allí desde 2018. Esta publicación de blog comparte nuestro viaje para resolver este problema y la solución final.

Un cambio largamente esperado

Con más funciones introducidas en la extensión de Java en Visual Studio Code, el número de nuestros usuarios también está aumentando constantemente. Sin embargo, debido al problema de que la extensión Java genera archivos de metadatos en el directorio del proyecto al importar el proyecto, hemos recibido mucha frustración por parte de los usuarios. A medida que aumenta la base de usuarios, es probable que este problema también cause un impacto negativo para más usuarios.

De hecho, esto no se debe a que nuestro equipo de producto no quiera solucionar este problema por completo. La causa raíz comienza con la arquitectura de Java Language Services:

Arquitectura LS

Diagrama de arquitectura de JDT Java Language Server 

El nombre oficial del proyecto del servicio de lenguaje Java utilizado detrás del proyecto VS Code Java es  Eclipse JDT Language Server ™  , que fue desarrollado conjuntamente por Microsoft y Red Hat. Como puede ver en el diagrama de arquitectura del proyecto anterior, reutilizamos algunos módulos de Eclipse en nuestra implementación, y estos archivos de metadatos generados automáticamente también son generados por algunos de los módulos anteriores. Se puede encontrar un hilo de discusión relacionado  en el área de discusión de Eclipse. La creación de esta publicación se remonta incluso a 2004. Dado que la ruta de estos archivos de metadatos se ha codificado de forma rígida en el código como constantes durante la implementación, varios módulos de Eclipse e incluso complementos han hecho referencia a estas constantes. A lo largo de los años, este problema se ha convertido en una “deuda técnica histórica”.

Teniendo en cuenta que cambiar el comportamiento de los módulos ascendentes puede introducir muchas incertidumbres, en el pasado intentamos proporcionar a los usuarios algunas soluciones, como ocultar estos archivos de metadatos en el explorador de archivos de VS Code y guiar a los usuarios para que los agreguen a .gitignore. Pero según los comentarios de los usuarios, estos métodos no satisfacían a los usuarios. Para resolver por completo este problema que ha estado molestando a los usuarios durante más de tres años, decidimos hacer otro intento en 2021 y ver si podemos encontrar una “cura”.

Opción 1: usar  enlace simbólico  (sin éxito)

El primer método que pensamos fue utilizar  Symbolic Link . Al importar un proyecto, puede vincular el proyecto importado a un lugar invisible para el usuario a través de Enlace simbólico, de modo que el archivo de metadatos se genere en la ruta vinculada. Pero pronto esta solución se topó con problemas: crear un enlace simbólico en ciertos sistemas operativos requiere permisos específicos; de lo contrario, se lanzará FileSystemException, que obviamente no es el efecto que queremos, por lo que esta solución se abandonó de inmediato.

Opción 2: usar  recursos vinculados de Eclipse  (sin éxito)

E ideas de enlace simbólico De forma similar, también podemos optar por utilizar los recursos enlazados de Eclipse:

Recursos vinculados  : los recursos vinculados son archivos y carpetas que se almacenan en ubicaciones en el sistema de archivos fuera de la ubicación del proyecto.

Esta es la definición oficial de recursos vinculados. Se puede usar como parte del proyecto, pero se puede almacenar en otras ubicaciones fuera de la ruta del proyecto. En las extensiones Java de VS Code, para la carpeta no administrada (proyecto sin un sistema de compilación), estos archivos de metadatos se ocultan a través del mecanismo de recursos vinculados. Su principio de implementación se muestra en la siguiente figura:

Recursos vinculados

Principios de la implementación de carpetas no administradas 

Puede ver que la ruta real del proyecto se coloca en el almacenamiento del espacio de trabajo del servidor de idiomas, el usuario generalmente no conoce esta ruta y en el archivo .project definimos la ruta de destino de los recursos vinculados, que es la carpeta abierta por el usuario en VS Code Location, como parte del proyecto, participará en el proceso de construcción como otros proyectos, y su experiencia de desarrollo es similar.

El mismo principio se puede aplicar al proceso de importación del proyecto Maven y el proyecto Gradle para resolver este problema. Por lo tanto, realizamos algunos experimentos en el módulo M2E. El módulo M2E es responsable de la importación del proyecto Maven en Java Language Service. Al modificar el código relevante en el módulo y utilizar el mecanismo de recursos vinculados, el archivo de metadatos se puede generar fuera de la ruta del proyecto.

Los resultados experimentales finales son factibles, pero las deficiencias de este enfoque también son muy obvias:

  • Gran cantidad de cambios : el código que debe cambiarse se encuentra disperso en diferentes archivos (alrededor de una docena de lugares) en todo el módulo. Al mismo tiempo, debido al gran tamaño del código, no hay forma de determinar si estos cambios se completarán en poco tiempo.
  • No es transparente para los módulos posteriores : debido a que hay una capa adicional de Carpeta Vinculada, esto generará una capa adicional que representa la estructura de directorio de la Carpeta Vinculada en el Explorador de Proyectos de Java. En la implementación de la vista del proyecto Java, es necesario agregar alguna lógica de control adicional para que la visualización de la estructura del proyecto sea la misma que la del proyecto normal.
  • Viabilidad desconocida : los módulos de soporte M2E y Buildship de los sistemas de compilación Maven y Gradle son proyectos ascendentes. Se desconoce si este concepto se puede adoptar o no.
  • Escalabilidad deficiente : si desea admitir un nuevo sistema de compilación, debe implementar una lógica similar nuevamente.

Teniendo en cuenta esos factores, el equipo decidió abandonar temporalmente el enfoque de recursos vinculados de Eclipse después de una discusión y continuó buscando una mejor solución.

Descubriendo el “S ilver Bullet 

Hay otra razón para abandonar el segundo enfoque: veinte años desde que se lanzó Eclipse, al tiempo que garantiza un funcionamiento estable, muestra la capacidad de agregar continuamente nuevas funciones y proporcionar excelentes capacidades de extensión, lo que indica una excelente arquitectura en términos de diseño y escalabilidad. Intuitivamente, creemos que debe haber una solución más elegante.

Por lo tanto, esta vez analizamos directamente el sistema de archivos subyacente de Eclipse, y finalmente encontramos una “bala de plata” para resolver el problema: Proveedor de sistema de archivos y FileStore (Nota: aunque en el campo de la ingeniería de software, el consenso es que no existe bala de plata. Pero para este problema en particular, encontramos una solución interesante).

Estructura del espacio de trabajo de Eclipse  y  FileStore 

Eclipse mantiene una estructura de árbol para todo el espacio de trabajo durante la operación. Los nodos del árbol representan archivos o directorios en el sistema de archivos, y también se guarda cierta información importante sobre los archivos, como la hora de modificación.

La capa inferior de Eclipse asocia estos nodos con archivos en el sistema de archivos a través de la clase FileStore. La clase FileStore tiene otra característica importante: si el objeto mapeado es un solo archivo, FileStore también será responsable de proporcionar los flujos de entrada y salida de este archivo.

Esta característica aporta una idea muy importante para la solución del problema: siempre que los flujos de entrada y salida del archivo de metadatos se puedan redirigir a una ubicación fuera del directorio del proyecto, el problema puede resolverse. Con esta suposición, encontramos otra pista clave:  Proveedor de sistema de archivos .

Solución: proveedor de sistema de archivos

El proveedor de sistema de archivos es un punto de extensión abierto a la plataforma Eclipse. Permite a los desarrolladores implementar una interfaz de sistema de archivos Eclipse (org.eclipse.core.filesystem.IFileSystem) y registrarla en el punto de extensión para manejar la solicitud de archivos con un esquema URI específico.

Entonces, comenzamos desde el punto de extensión del Proveedor de sistema de archivos, heredamos y anulamos el sistema de procesamiento de archivos predeterminado en Eclipse. Al anular algunos de estos métodos, el sistema de archivos redirige la ruta del archivo cuando procesa archivos de metadatos y lee / escribe en un lugar fuera de la ruta del proyecto. En comparación con la segunda opción, las ventajas de este enfoque son:

  • Es completamente transparente para otros módulos  y puede funcionar normalmente sin modificaciones, lo que también significa una mejor  escalabilidad  .
  • La cantidad de cambio de código es muy pequeña y la implementación final  , incluidos JavaDoc y los comentarios, tiene solo unas 300 líneas en total.

Por supuesto, esta solución no es perfecta, porque requiere otros módulos para leer y escribir archivos de metadatos a través de la API proporcionada por Eclipse. Encontramos un cambio ascendente durante la implementación que Buildship utiliza directamente la API de E / S en el JDK para procesar archivos de metadatos , y hemos presentado una  solicitud de extracción de migrar dichas operaciones a la API de Eclipse.