Skip to content

Updating class references (generated classes from proto files) #1482

Open

Description

@badsyntax

Hi. I'm using Protocol Buffers in my Java application. I'm using Gradle, and the protobuf-gradle-plugin to generate Java classes from the .proto files. The generated proto Java files are added to my sourceSet in build.gradle.

build.gradle
plugins {
    id 'java'
    id 'application'
    id "com.google.protobuf" version "0.8.12"
}

repositories {
    jcenter()
}

dependencies {
    implementation 'com.google.guava:guava:28.2-jre'
    testImplementation 'junit:junit:4.12'
}

application {
    mainClassName = 'test.gradle.project.proto.App'
}

sourceSets {
  main {
    java {
      srcDirs 'src/main/java'
      srcDirs 'build/generated/source/proto/main/java'
    }
  }
}

compileJava.dependsOn 'generateProto'

Whenever I make a change to the proto files, and re-generate the proto Java classes via ./gradlew generateProto, the language server does not update the references, and I get errors in the editor. AFAIK there's two ways to update the class references:

  1. Restart vscode, or
  2. Run "Update project configuration" from the grade build file

Neither options are ideal, and option 2 can sometimes take a long time to complete on large projects. I would think updating class references should be a quick process. No compilation is necessary, the language server just needs to update it's reference cache (or something along those lines).

Would it be possible to

  1. Provide a new command to update class references?
  2. Watch the build directory/sourceSets and automatically update references when generated files change?

I'm also developing a gradle vscode extension, and from my extension i would potentially be able to provide a list of generated class files to the vscode-java extension via an API call, so that could also be a potential option.

Looking for any ideas/suggestions/changes to make this process more user friendly and fast.

Environment
  • Operating System: MacOS catalina
  • JDK version: openjdk 11.0.2
  • Visual Studio Code version: 1.45.1
  • Java extension version: 0.62.0
Steps To Reproduce
  1. Clone this repo: https://github.com/badsyntax/test-gradle-project-proto
  2. Open test-gradle-project-proto in vscode
  3. Open src/main/java/test/gradle/project/proto/App.java
  4. Note classes for Greeting don't exist
  5. In the vscode terminal, run ./gradlew generateProto
  6. Note references for Greeting still don't exist
  7. Either restart vscode, or run "Update project configuration" from build.gradle
  8. Note references for Greeting now exist and there's no errors in the editor

Keep in mind this is a very small project and you won't see the performance issues I mentioned above, but does demonstrate the extension not updating references when files on disk change.

Activity

  1. testforstephen commented on Jun 5, 2020

    @testforstephen
    Collaborator

    "Update project configuration" is exactly used to update classpath. Its performance issue is covered at another issue #1362.

  2. badsyntax commented on Jun 5, 2020

    @badsyntax
    Author

    I don't know the internals of how this extension works, but it seems that "Update project configuration" does more than just update classpath (eg I don't know what "project configuration" means):

    Java:Update Project configuration (Shift+Alt+U): is available when the editor is focused on a Maven pom.xml or a Gradle file. It forces project configuration / classpath updates (eg. dependency changes or Java compilation level), according to the project build descriptor.

    But ignoring the performance and focusing in the UX, running this command is not an ideal step. I need to either focus on the build.gradle file before running it, or right click the build.gradle file in the explorer and select "Update project configuration".
    Working with others, I've also noticed that this is not an obvious step and causes confusion & frustration for users (it was also confusing behaviour for me when I first used the extension).

    My expectation is the extension should update the references when the classes change on disk.

    If this extension already knows which files are in the classpath (eg as defined in the sourceSets block in my build.gradle), why can't it automatically compile the classes and update the references in the editor when those files change?

    For the test repo I linked above, the .classpath file has this entry (as defined in sourceSets):

    <classpathentry kind="src" output="bin/main" path="build/generated/source/proto/main/java">
    	<attributes>
    		<attribute name="gradle_scope" value="main"/>
    		<attribute name="gradle_used_by_scope" value="main,test"/>
    	</attributes>
    </classpathentry>

    ..so it seems like the extension should be able to watch those files and update references when the classes change. This would be a huge UX improvement.

  3. testforstephen commented on Jun 5, 2020

    @testforstephen
    Collaborator

    The extension will auto watch on those files under the folder which is marked as src kind in .classpath.

    When i tried your sample project at first time, actually the .classpath file didn't contain the sourceSets you pasted above. Only when i run ./gradlew generateProto and "Update project configuratoin", then the sourceSets entry above is added to .classpath. So looks like the .classpath cannot contain not existing folder.

    Once your new sourceSets is included in .classpath, you are supposed not need to update project configuration manually. Because the extension will auto watch on the files listed by .classpath, and sync up them.

    Regarding UX, i'm open to new idea to make it better.

  4. badsyntax commented on Jun 5, 2020

    @badsyntax
    Author

    Thanks for testing this. You're totally right, it does indeed watch those files and update references. This is great. Apologies for not spotting this behaviour. I remember it didn't always do this, perhaps this is a recent change in the extension? Either way, this is exactly what I was looking for haha 🤦

    About the .classpath not containing references to paths that don't exist, do you happen to know why? As i've defined a classpath via sourceSet, i would expect the extension to add this path to the .classpath, regardless if the path exists or not. Is this something that can be changed, to support classes being added to the classpath at a later time?

  5. badsyntax commented on Jun 15, 2020

    @badsyntax
    Author

    hi @testforstephen have you had a chance to look into this? Am wondering why the extension doesn't add paths from the sourceSets (that don't exist) into the .classpath? This would help with the UX of this extension.

  6. testforstephen commented on Jun 16, 2020

    @testforstephen
    Collaborator

    We're leveraging buildship to support gradle project, don't get time to look into the upstream buildship tool yet.

  7. lfarkas commented on Feb 1, 2023

    @lfarkas

    is there any progress with this? for me it's still not working...

  8. Mr-EmPee commented on Jul 17, 2026

    @Mr-EmPee

    This problem still seems to exists, I found out that after running a compileJava (that also compile the protos) and then Java: reload projects it works.

    Is there any chance of this being fixed?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions