[Java] [Memorandum] A story that I was addicted to changing Java build tools with VS Code

4 minute read

Introduction

I was coding Java in VS Code and was addicted to solving Dependency. As a reminder (I think I’ll be addicted to it again), I will describe the process of the investigation.

It happened after I rewrite pom.xml in good condition, trying to remodel the Spring Boot sample code that I cloned from GitHub, which I did.

“Isn’t the added dependency reflected in VS Code?”

From there, the investigation started.

Investigation

The Java-related extensions introduced in VS Code are only Java Extension Pack, so if you have a problem with Java Extension Pack, you should know it from the public (*Google).

However, even if you ask the opinion of people (*Stack Overflow), if you update pom.xml, a confirmation dialog like “Do you want to reflect the update?” will appear and it will be reflected properly.

The only possibility was that there was a problem with the Java Language Server’s cache and I should clear it.

let’s do it.

Coping 1 (Failure)

The VS Code environment in question uses Remote-WLS to run on Ubuntu with WLS2. VS Code cache data is placed in the following location.

~/.vscode-server/data/User/workspaceStorage/

Exit VS Code once, access the Ubuntu terminal from Windows Terminal, and delete the cache data. Then restart VS Code. If it’s a cache problem, this should solve the problem. To be honest, I thought I won. Well, if that worked out, we wouldn’t be addicted to the behavior of the tool, and I wouldn’t write such an article, so that thought was just an illusion.

Not surprisingly, the dependencies haven’t been updated on the restarted VS Code. I tried mvn compile etc. in vain, but it’s completely unresponsive. When I thought it was a choke, I suddenly remembered something. Yes, I don’t remember seeing any of the example dialogs that should appear when I edit pom.xml.

The thought of running around my head. This sample code can be built not only with maven but also with gradle. Since I’m not usually a gradle group, bundle.gradle, which I pretended not to see completely, is also attached to this sample code… At the same level as pom.xml.

.classpath


<?xml version="1.0" encoding="UTF-8"?>
<classpath>
     <classpathentry kind="src" output="bin/main" path="src/main/java">
         <attributes>
             <attribute name="gradle_scope" value="main"/>
             <attribute name="gradle_used_by_scope" value="main,test"/>
        </attributes>
    </classpathentry>
     <classpathentry kind="src" output="bin/test" path="src/test/java">
         <attributes>
             <attribute name="gradle_scope" value="test"/>
             <attribute name="gradle_used_by_scope" value="test"/>
             <attribute name="test" value="true"/>
        </attributes>
    </classpathentry>
     <classpathentry kind="src" output="bin/main" path="src/main/resources">
         <attributes>
             <attribute name="gradle_scope" value="main"/>
             <attribute name="gradle_used_by_scope" value="main,test"/>
        </attributes>
    </classpathentry>
     <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8/"/>
     <classpathentry kind="con" path="org.eclipse.buildship.core.gradleclasspathcontainer"/>
     <classpathentry kind="output" path="bin/default"/>
</classpath>

Unexpectedly, I half laughed. Actually, I was addicted to this problem for less than two hours. It’s a painful blow. There is no place to hit this unfocused feeling. This .classpath is a file for specifying the directories and libraries to be included in the target for VS Code side dependency resolution, and is automatically generated. Then, no matter how much maven’s pom.xml is rewritten, the dependency is not reflected. It hasn’t been referenced from the beginning… hah (´・ω・`)

There are two ways to solve this phenomenon. ・ Obediently switch the build tool to gradle.

  • Regenerate .classpath so that the dependency is forcibly referenced by maven.

Countermeasure 2 (failure again)

Since it was bad to get down to the gradle army, I will choose the latter without hesitation. I quit VS Code and mvd .classpath and build.gradle from the terminal. With this, when you restart, .classpath based on maven … is not created, right? Hmm?

I was a bit worried, but the culprit was .project.

.project


<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
     <name>spring-boot</name>
    <comment>Project complete created by by Buildship.</comment>
     <projects>
    </projects>
     <buildSpec>
         <buildCommand>
             <name>org.eclipse.jdt.core.javabuilder</name>
             <arguments>
            </arguments>
        </build Command>
         <buildCommand>
             <name>org.eclipse.buildship.core.gradleprojectbuilder</name>
             <arguments>
            </arguments>
        </build Command>
    </buildSpec>
     <natures>
         <nature>org.eclipse.jdt.core.javanature</nature>
         <nature>org.eclipse.buildship.core.gradleprojectnature</nature>
    </natures>
</projectDescription>

It says gradle as much as you want. Let’s mv this too. Restart VS Code. This time, the dependency was reflected properly based on maven. However, .project and .classpath are not generated… There is no problem in coding, but it’s very unpleasant. It can also cause you to get hooked.

Besides, I also care about when .project and .classpath are generated. Let’s verify.

Verification

Create another directory and clone again from the original GitHub repository. If you open it in VS Code, it’s generated.

This is the state of the target directory just cloned image.png

This is the state after VS Code is started. At this point a .project was already generated and the internals were written to use gradle. There is also a .classpath. As a matter of course, it started to use gradle. Apparently, gradle has priority over maven.

image.png

The following files and directories are added. .Classpath ..Gradle ..Project ..Settings ・Bin In other words, as VS Code, when you open the directory, you choose (probably) build.gradle to use that as your build tool, generate a .project file, and the project environment is automatically based on gradle. I think it means that it is set to the target. Now, let’s clone this project again and check the behavior when the build.gradle is deleted this time. The directory before opening VS Code looks like this.

image.png

When I opened it with VS Code, both .project and .classpath were generated.

.project


<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
     <name>spring-boot</name>
     <comment></comment>
     <projects>
    </projects>
     <buildSpec>
         <buildCommand><name>org.eclipse.jdt.core.javabuilder</name>
            <arguments>
            </arguments>
        </buildCommand>
        <buildCommand>
            <name>org.eclipse.m2e.core.maven2Builder</name>
            <arguments>
            </arguments>
        </buildCommand>
    </buildSpec>
    <natures>
        <nature>org.eclipse.jdt.core.javanature</nature>
        <nature>org.eclipse.m2e.core.maven2Nature</nature>
    </natures>
</projectDescription>

.classpath


<?xml version="1.0" encoding="UTF-8"?>
<classpath>
    <classpathentry kind="src" output="target/classes" path="src/main/java">
        <attributes>
            <attribute name="optional" value="true"/>
            <attribute name="maven.pomderived" value="true"/>
        </attributes>
    </classpathentry>
    <classpathentry kind="src" output="target/test-classes" path="src/test/java">
        <attributes>
            <attribute name="optional" value="true"/>
            <attribute name="maven.pomderived" value="true"/>
            <attribute name="test" value="true"/>
        </attributes>
    </classpathentry>
    <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8">
        <attributes>
            <attribute name="maven.pomderived" value="true"/>
        </attributes>
    </classpathentry>
    <classpathentry kind="con" path="org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER">
        <attributes>
            <attribute name="maven.pomderived" value="true"/>
        </attributes>
    </classpathentry>
    <classpathentry kind="src" path="target/generated-sources/annotations">
        <attributes>
            <attribute name="optional" value="true"/>
            <attribute name="maven.pomderived" value="true"/>
            <attribute name="ignore_optional_problems" value="true"/>
            <attribute name="m2e-apt" value="true"/>
        </attributes>
    </classpathentry>
    <classpathentry kind="src" output="target/test-classes" path="target/generated-test-sources/test-annotations">
        <attributes>
            <attribute name="optional" value="true"/>
            <attribute name="maven.pomderived" value="true"/>
            <attribute name="ignore_optional_problems" value="true"/>
            <attribute name="m2e-apt" value="true"/>
            <attribute name="test" value="true"/>
        </attributes>
    </classpathentry>
    <classpathentry kind="output" path="target/classes"/>
</classpath>

どちらもmavenベースに置き換わっています。私の目指すところはこれなのです。

対処3(成功)

それでは、一度VS Codeでgradleプロジェクトとして認識されてしまったものを、mavenプロジェクトとして再認識させるためには、なにが足りなかったのでしょうか。 先ほどgradleプロジェクトからbuild.gradleと.classpath、.projectをmvしましたが、他にも自動生成されたディレクトリや、gradle関連のリソースが含まれています。が、怪しいのは自動生成されたリソースです。 そのため、それらをやはり全てmvしてみましょう。…あれ、変更されませんね?

そこでピンと来ました。原因は.projectや.classpathをプロジェクトルート配下のbackupというディレクトリにmvしたことでした。どうも、.projectがルートディレクトリの配下になくても、サブディレクトリに存在していればそちらを読み込む、という仕様が存在するようです。 .projectと.classpathを削除することで、新しい.projectと.classpathが生成され、プロジェクトのビルドツールがmavenに切り替わりました。

まとめ

  • VS CodeのJava Extension Packでは、pom.xmlかbuild.gradleが存在しているディレクトリを初めて開いた際に、.projectが生成されJavaプロジェクトとして認識される。
  • build.gradleとpom.xmlの両方が存在していた場合には、gradleが優先される。
  • 一度ビルドツールが決定してしまった後は、VS Code側では変更する手段はない。(そのため、pom.xmlだけ修正するなどというおバカなことをやるとハマる)
  • ビルドツールを移行したい場合には、build.gradle以外にも、.projectと.classpathを削除してから再度VS Codeでディレクトリを開く必要がある。
  • mvとremoveは違う。

ということですね。ずいぶん遠回りしましたが、無事ビルドツールをmavenに切り替えることができました。

めでたし、めでたし。

とっぴんぱらりのぷう。