Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Toml ClassCastException #4890

Closed
jarasez opened this issue Jan 13, 2025 · 14 comments · Fixed by #4892
Closed

Toml ClassCastException #4890

jarasez opened this issue Jan 13, 2025 · 14 comments · Fixed by #4892
Labels
bug Something isn't working parser-toml

Comments

@jarasez
Copy link

jarasez commented Jan 13, 2025

What version of OpenRewrite are you using?

  • OpenRewrite v6.0.0
  • Maven/Gradle plugin v7.0.0
  • rewrite-spring v6.0.0

How are you running OpenRewrite?

Are you using the Maven plugin, Gradle plugin, Moderne CLI, Moderne.io or something else?
I am using the Gradle plugin, and my project is a single module project.
I am using toml files for managing dependency versions, with [bundles] tag.

Is your project a single module or a multi-module project?
The project is a single module

Is your project public? If so, can you share a link to it?
Managed to reproduce the bug, in this project: https://github.com/jarasez/openrewrite-toml

Can you share your configuration so that we can rule out any configuration issues?
libs.versions.toml

[versions]
jackson = '2.14.2'

spring-boot = '2.7.16'
spring-dependency-management = '1.0.14.RELEASE'
openrewrite = '7.0.0'

[libraries]
jackson-annotations = { module = 'com.fasterxml.jackson.core:jackson-annotations', version.ref = 'jackson' }
jackson-core = { module = 'com.fasterxml.jackson.core:jackson-core', version.ref = 'jackson' }
jackson-databind = { module = 'com.fasterxml.jackson.core:jackson-databind', version.ref = 'jackson' }

[bundles]
jackson = ['jackson-annotations', 'jackson-core', 'jackson-databind']

[plugins]
spring-boot = { id = 'org.springframework.boot', version.ref = 'spring-boot' }
spring-boot-dependency-management = { id = 'io.spring.dependency-management', version.ref = 'spring-dependency-management' }
openrewrite = { id = 'org.openrewrite.rewrite', version.ref = 'openrewrite' }

build.gradle

plugins {
    id 'java'
    alias(libs.plugins.spring.boot)
    alias(libs.plugins.spring.boot.dependency.management)
    alias(libs.plugins.openrewrite)
}

group = 'test.openrewrite'
version = '0.0.1-SNAPSHOT'

java {
    toolchain {
        languageVersion = JavaLanguageVersion.of(17)
    }
}

repositories {
    mavenCentral()
}

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter'
    implementation libs.bundles.jackson

    rewrite("org.openrewrite.recipe:rewrite-spring:6.0.0")

    testImplementation 'org.springframework.boot:spring-boot-starter-test'
    testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
}

tasks.named('test') {
    useJUnitPlatform()
}

rewrite {
    activeRecipe("org.openrewrite.java.spring.boot3.UpgradeSpringBoot_3_3")
//    activeRecipe("org.openrewrite.java.spring.boot3.SpringBootProperties_3_3")
//    activeRecipe("org.openrewrite.java.spring.boot3.MigrateThymeleafDependencies")
//    activeRecipe("org.openrewrite.java.spring.boot3.ActuatorEndpointSanitization")
//    activeRecipe("org.openrewrite.java.spring.boot3.SpringBoot3BestPractices")

    setExportDatatables(true)
}

What is the smallest, simplest way to reproduce the problem?

Run gradle task rewriteRun.

What did you expect to see?

Successful execution of the gradle task rewriteRun. It seems that the [bundles] section of the toml causes the exception bellow.

What did you see instead?

The gradle task rewriteRun fails.

What is the full stack trace of any errors you encountered?

Caused by: org.openrewrite.internal.RecipeRunException: java.lang.ClassCastException: class org.openrewrite.toml.tree.Toml$Literal cannot be cast to class org.openrewrite.toml.tree.TomlValue (org.openrewrite.toml.tree.Toml$Literal and org.openrewrite.toml.tree.TomlValue are in unnamed module of loader org.openrewrite.gradle.RewriteClassLoader @41666a7d)
        at org.openrewrite.TreeVisitor.visit(TreeVisitor.java:290)
        at org.openrewrite.toml.TomlVisitor.visitKeyValue(TomlVisitor.java:73)
        at org.openrewrite.toml.tree.Toml$KeyValue.acceptToml(Toml.java:228)
        at org.openrewrite.toml.tree.Toml.accept(Toml.java:37)
        at org.openrewrite.TreeVisitor.visit(TreeVisitor.java:250)
        at org.openrewrite.toml.TomlVisitor.lambda$visitTable$2(TomlVisitor.java:92)
        at org.openrewrite.internal.ListUtils.map(ListUtils.java:243)
        at org.openrewrite.internal.ListUtils.map(ListUtils.java:265)
        at org.openrewrite.toml.TomlVisitor.visitTable(TomlVisitor.java:92)
        at org.openrewrite.toml.tree.Toml$Table.acceptToml(Toml.java:327)
        at org.openrewrite.toml.tree.Toml.accept(Toml.java:37)
        at org.openrewrite.TreeVisitor.visit(TreeVisitor.java:250)
        at org.openrewrite.toml.TomlVisitor.lambda$visitTable$2(TomlVisitor.java:92)
        at org.openrewrite.internal.ListUtils.map(ListUtils.java:243)
        at org.openrewrite.internal.ListUtils.map(ListUtils.java:265)
        at org.openrewrite.toml.TomlVisitor.visitTable(TomlVisitor.java:92)
        at org.openrewrite.toml.tree.Toml$Table.acceptToml(Toml.java:327)
        at org.openrewrite.toml.tree.Toml.accept(Toml.java:37)
        at org.openrewrite.TreeVisitor.visit(TreeVisitor.java:250)
        at org.openrewrite.toml.TomlVisitor.lambda$visitTable$2(TomlVisitor.java:92)
        at org.openrewrite.internal.ListUtils.map(ListUtils.java:243)
        at org.openrewrite.internal.ListUtils.map(ListUtils.java:265)
        at org.openrewrite.toml.TomlVisitor.visitTable(TomlVisitor.java:92)
        at org.openrewrite.toml.tree.Toml$Table.acceptToml(Toml.java:327)
        at org.openrewrite.toml.tree.Toml.accept(Toml.java:37)
        at org.openrewrite.TreeVisitor.visit(TreeVisitor.java:250)
        at org.openrewrite.toml.TomlVisitor.lambda$visitDocument$1(TomlVisitor.java:49)
        at org.openrewrite.internal.ListUtils.map(ListUtils.java:243)
        at org.openrewrite.internal.ListUtils.map(ListUtils.java:265)
        at org.openrewrite.toml.TomlVisitor.visitDocument(TomlVisitor.java:49)
        at org.openrewrite.toml.tree.Toml$Document.acceptToml(Toml.java:149)
        at org.openrewrite.toml.tree.Toml.accept(Toml.java:37)
        at org.openrewrite.TreeVisitor.visit(TreeVisitor.java:250)
        at org.openrewrite.gradle.isolated.ResultsContainer.getRecipeErrors(ResultsContainer.java:107)
        at org.openrewrite.gradle.isolated.ResultsContainer.getFirstException(ResultsContainer.java:87)
        at org.openrewrite.gradle.isolated.DefaultProjectParser.run(DefaultProjectParser.java:416)
        at org.openrewrite.gradle.isolated.DefaultProjectParser.run(DefaultProjectParser.java:409)
        at org.openrewrite.gradle.DelegatingProjectParser.lambda$run$2(DelegatingProjectParser.java:104)
        at org.openrewrite.gradle.DelegatingProjectParser.unwrapInvocationException(DelegatingProjectParser.java:153)
        ... 122 more

Are you interested in [contributing a fix to OpenRewrite]

I can get involved.

@jarasez jarasez added the bug Something isn't working label Jan 13, 2025
@timtebeek
Copy link
Contributor

Thanks for trying out the new toml parser, and the detailed failure report @jarasez ! Curious case indeed. I've briefly tried to replicate the issue with a unit test, but this passes so far:

@Issue("https://github.com/openrewrite/rewrite/issues/4890")
@Test
void literalClassCastException(){
    rewriteRun(
      toml(
        """
        [versions]
        jackson = '2.14.2'
        
        spring-boot = '2.7.16'
        spring-dependency-management = '1.0.14.RELEASE'
        openrewrite = '7.0.0'
        
        [libraries]
        jackson-annotations = { module = 'com.fasterxml.jackson.core:jackson-annotations', version.ref = 'jackson' }
        jackson-core = { module = 'com.fasterxml.jackson.core:jackson-core', version.ref = 'jackson' }
        jackson-databind = { module = 'com.fasterxml.jackson.core:jackson-databind', version.ref = 'jackson' }
        
        [bundles]
        jackson = ['jackson-annotations', 'jackson-core', 'jackson-databind']
        
        [plugins]
        spring-boot = { id = 'org.springframework.boot', version.ref = 'spring-boot' }
        spring-boot-dependency-management = { id = 'io.spring.dependency-management', version.ref = 'spring-dependency-management' }
        openrewrite = { id = 'org.openrewrite.rewrite', version.ref = 'openrewrite' }
        """
      )
    );
}

Any help to trouble shoot this would be appreciated!

@timtebeek timtebeek transferred this issue from openrewrite/rewrite-spring Jan 13, 2025
@jarasez
Copy link
Author

jarasez commented Jan 13, 2025

Maybe it is a org.openrewrite.java.spring.boot3.UpgradeSpringBoot_3_3 recipe issue? is there a way to add the recipe to the test? Is running ./gradle rewriteRun on the repo link working for you?

@timtebeek
Copy link
Contributor

Turns out it's an issue with the visitor, which we hadn't tested previously. This test indeed fails already.

import org.junit.jupiter.api.Test;
import org.openrewrite.*;
import org.openrewrite.marker.Markup;
import org.openrewrite.test.RewriteTest;

import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

import static org.openrewrite.test.RewriteTest.toRecipe;
import static org.openrewrite.toml.Assertions.toml;

class TomlVisitorTest implements RewriteTest {

    @Issue("https://github.com/openrewrite/rewrite-spring/issues/665")
    @Test
    void visit() {
        List<RuntimeException> exceptions = new ArrayList<>();
        rewriteRun(
          spec -> spec.recipe(toRecipe(() -> new TreeVisitor<>() {
              @Override
              public Tree preVisit(Tree tree, ExecutionContext ctx) {
                  tree.getMarkers().findFirst(Markup.Error.class).ifPresent(e -> {
                      Optional<SourceFile> sourceFile = Optional.ofNullable(getCursor().firstEnclosing(SourceFile.class));
                      String sourcePath = sourceFile.map(SourceFile::getSourcePath).map(Path::toString).orElse("<unknown>");
                      exceptions.add(new RuntimeException("Error while visiting " + sourcePath + ": " + e.getDetail()));
                  });
                  return tree;
              }
          })),
          toml(
            """
              [versions]
              jackson = '2.14.2'
              
              spring-boot = '2.7.16'
              spring-dependency-management = '1.0.14.RELEASE'
              openrewrite = '7.0.0'
              
              [libraries]
              jackson-annotations = { module = 'com.fasterxml.jackson.core:jackson-annotations', version.ref = 'jackson' }
              jackson-core = { module = 'com.fasterxml.jackson.core:jackson-core', version.ref = 'jackson' }
              jackson-databind = { module = 'com.fasterxml.jackson.core:jackson-databind', version.ref = 'jackson' }
              
              [bundles]
              jackson = ['jackson-annotations', 'jackson-core', 'jackson-databind']
              
              [plugins]
              spring-boot = { id = 'org.springframework.boot', version.ref = 'spring-boot' }
              spring-boot-dependency-management = { id = 'io.spring.dependency-management', version.ref = 'spring-dependency-management' }
              openrewrite = { id = 'org.openrewrite.rewrite', version.ref = 'openrewrite' }
              """
          )
        );
    }
}

@timtebeek
Copy link
Contributor

Let's continue on this PR containing the above unit test:

@github-project-automation github-project-automation bot moved this from Backlog to Done in OpenRewrite Jan 13, 2025
@timtebeek
Copy link
Contributor

Thanks again for the report @jarasez ; Turns out that the cast that tripped us up here was too strict for array values. Should go out with the next release.

@jarasez
Copy link
Author

jarasez commented Jan 15, 2025

@timtebeek thanks for the fix, tested with gradle plugin version 7.0.1, however I still get the same error however at another line.
It seems that TomlVisitor on line 73 is calling: visitAndCast((J) left.getElement(), p)
which throws the exception.
I also updated the repo in the bug description to gradle plugin version 7.0.1.

Caused by: org.openrewrite.internal.RecipeRunException: java.lang.ClassCastException: class org.openrewrite.toml.tree.Toml$Literal cannot be cast to class org.openrewrite.toml.tree.TomlValue (org.openrewrite.toml.tree.Toml$Literal and org.openrewrite.toml.tree.TomlValue are in unnamed module of loader org.openrewrite.gradle.RewriteClassLoader @47e95881)
        at org.openrewrite.TreeVisitor.visit(TreeVisitor.java:290)
        at org.openrewrite.toml.TomlVisitor.visitKeyValue(TomlVisitor.java:73)
        at org.openrewrite.toml.tree.Toml$KeyValue.acceptToml(Toml.java:228)
        at org.openrewrite.toml.tree.Toml.accept(Toml.java:37)
        at org.openrewrite.TreeVisitor.visit(TreeVisitor.java:250)
        at org.openrewrite.toml.TomlVisitor.lambda$visitTable$2(TomlVisitor.java:92)
        at org.openrewrite.internal.ListUtils.map(ListUtils.java:243)
        at org.openrewrite.internal.ListUtils.map(ListUtils.java:265)
        at org.openrewrite.toml.TomlVisitor.visitTable(TomlVisitor.java:92)
        at org.openrewrite.toml.tree.Toml$Table.acceptToml(Toml.java:327)
        at org.openrewrite.toml.tree.Toml.accept(Toml.java:37)
        at org.openrewrite.TreeVisitor.visit(TreeVisitor.java:250)
        at org.openrewrite.toml.TomlVisitor.lambda$visitTable$2(TomlVisitor.java:92)
        at org.openrewrite.internal.ListUtils.map(ListUtils.java:243)
        at org.openrewrite.internal.ListUtils.map(ListUtils.java:265)
        at org.openrewrite.toml.TomlVisitor.visitTable(TomlVisitor.java:92)
        at org.openrewrite.toml.tree.Toml$Table.acceptToml(Toml.java:327)
        at org.openrewrite.toml.tree.Toml.accept(Toml.java:37)
        at org.openrewrite.TreeVisitor.visit(TreeVisitor.java:250)
        at org.openrewrite.toml.TomlVisitor.lambda$visitTable$2(TomlVisitor.java:92)
        at org.openrewrite.internal.ListUtils.map(ListUtils.java:243)
        at org.openrewrite.internal.ListUtils.map(ListUtils.java:265)
        at org.openrewrite.toml.TomlVisitor.visitTable(TomlVisitor.java:92)
        at org.openrewrite.toml.tree.Toml$Table.acceptToml(Toml.java:327)
        at org.openrewrite.toml.tree.Toml.accept(Toml.java:37)
        at org.openrewrite.TreeVisitor.visit(TreeVisitor.java:250)
        at org.openrewrite.toml.TomlVisitor.lambda$visitDocument$1(TomlVisitor.java:49)
        at org.openrewrite.internal.ListUtils.map(ListUtils.java:243)
        at org.openrewrite.internal.ListUtils.map(ListUtils.java:265)
        at org.openrewrite.toml.TomlVisitor.visitDocument(TomlVisitor.java:49)
        at org.openrewrite.toml.tree.Toml$Document.acceptToml(Toml.java:149)
        at org.openrewrite.toml.tree.Toml.accept(Toml.java:37)
        at org.openrewrite.TreeVisitor.visit(TreeVisitor.java:250)
        at org.openrewrite.gradle.isolated.ResultsContainer.getRecipeErrors(ResultsContainer.java:107)
        at org.openrewrite.gradle.isolated.ResultsContainer.getFirstException(ResultsContainer.java:87)
        at org.openrewrite.gradle.isolated.DefaultProjectParser.run(DefaultProjectParser.java:416)
        at org.openrewrite.gradle.isolated.DefaultProjectParser.run(DefaultProjectParser.java:409)
        at org.openrewrite.gradle.DelegatingProjectParser.lambda$run$2(DelegatingProjectParser.java:104)
        at org.openrewrite.gradle.DelegatingProjectParser.unwrapInvocationException(DelegatingProjectParser.java:153)
        ... 122 more

@knutwannheden
Copy link
Contributor

The correct place is here:

kv = kv.withValue(visit(kv.getValue(), p));

I suspect that Literal should implement the TomlValue interface.

/cc @shanman190

@shanman190
Copy link
Contributor

So originally, I was using TomlValue to demark the actual values that could be represented in a toml file (KeyValue and Table). A Literal cannot appear on its own in a TOML document unlike it can within a JSON document.

...still assessing the correct fix...

@shanman190
Copy link
Contributor

The original stacktrace and the latest stacktrace from 7.0.1 appear to be identical. Not sure if that was an accidental copy/paste or not. It does make me suspicious that the example is using the old version of the rewrite-toml code still with the cast that Tim removed.

@jarasez
Copy link
Author

jarasez commented Jan 15, 2025

@shanman190 thank you. you are right, it's the same line with error. I updated the gradle plugin library, then I ran: gradle rewriteRun. should I do anything else except updating the gradle plugin?

@shanman190
Copy link
Contributor

shanman190 commented Jan 15, 2025

The release process is supposed to capture the latest available versions of transitive dependencies at the time of the release, so typically just updating the plugin is enough.

Regardless, you should be able to set the rewriteVersion extension property or include the latest rewrite-toml dependency in your rewrite Gradle configuration to result in those fixes coming in.

@jarasez
Copy link
Author

jarasez commented Jan 15, 2025

@shanman190 checked main branch and ran the test @timtebeek created and saw that the test goes through:

org.openrewrite.toml.TomlVisitor.visitTable(TomlVisitor.java:92)
at org.openrewrite.toml.tree.Toml$Table.acceptToml(Toml.java:149) 
org.openrewrite.toml.tree.Toml.accept(Toml.java:37)

However in the pasted stacktrace it goes through:

org.openrewrite.toml.TomlVisitor.visitDocument(TomlVisitor.java:49)
at org.openrewrite.toml.tree.Toml$Document.acceptToml(Toml.java:149)
at org.openrewrite.toml.tree.Toml.accept(Toml.java:37)

Looking at the class TomlVisitor seems there is a cast to (TomlValue) on line 49.

d = d.withValues(ListUtils.map(d.getValues(), v -> (TomlValue) visit(v, p)));

Maybe that is the issue when running with gradle instead of the test?

@shanman190
Copy link
Contributor

So that section is iterating over the values of the Toml.Document which will always be TomlValue instances.

@jarasez
Copy link
Author

jarasez commented Jan 15, 2025

worked by adding rewrite("org.openrewrite:rewrite-toml:8.43.1")
thanks for all the help

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working parser-toml
Projects
Archived in project
Development

Successfully merging a pull request may close this issue.

4 participants