cincheo / jsweet

A Java to JavaScript transpiler.
http://www.jsweet.org
Other
1.45k stars 159 forks source link

"a cycle was detected in static intializers" error when making a java candy #741

Open tonychunxizhu opened 1 year ago

tonychunxizhu commented 1 year ago

there are only 2 files in this candy Token.java

package com.test.candies;

abstract class Token {
    static final Token TEST = new SimpleToken(200, 200);
    Token(int  t) {
        System.out.println("Token");
        System.out.println(t);
    }
}

and SimpleToken.java

package com.test.candies;
final class SimpleToken  extends Token {
    SimpleToken(int a, int b) {
        super(a);
        System.out.println("SimpleToken");
        System.out.println(a );
    }
}

error message

...
2022-09-26 14:35:10.010 DEBUG StaticInitilializerAnalyzer:192 - adding static initializer dependency: SimpleFileObject[D:\jsweet\javacandy\src\main\java\com\test\candies\Token.java] -> SimpleFileObject[D:\jsweet\javacandy\src\main\java\com\test\candies\SimpleToken.java]
ERROR: a cycle was detected in static intializers involving '[D:\jsweet\javacandy\src\main\java\com\test\candies\SimpleToken.java, D:\jsweet\javacandy\src\main\java\com\test\candies\Token.java]'
cycle: [D:\jsweet\javacandy\src\main\java\com\test\candies\SimpleToken.java, D:\jsweet\javacandy\src\main\java\com\test\candies\Token.java]
cycle: [D:\jsweet\javacandy\src\main\java\com\test\candies\Token.java, D:\jsweet\javacandy\src\main\java\com\test\candies\SimpleToken.java]
2022-09-26 14:35:10.010 INFO  JSweetTranspiler:850 - transpilation process finished in 352 ms 
> java2ts: 336.9411ms
> ts2js: 9.0E-4ms

[ERROR] transpilation failed
org.apache.maven.plugin.MojoFailureException: transpilation failed with 1 error(s) and 0 warning(s)

=========================================
TRANSPILATION ERRORS SUMMARY:
* a cycle was detected in static intializers involving '[D:\jsweet\javacandy\src\main\java\com\test\candies\SimpleToken.java, D:\jsweet\javacandy\src\main\java\com\test\candies\Token.java]'

=========================================
    at org.jsweet.AbstractJSweetMojo.transpile (AbstractJSweetMojo.java:704)
    at org.jsweet.JSweetMojo.execute (JSweetMojo.java:45)
    at org.apache.maven.plugin.DefaultBuildPluginManager.executeMojo (DefaultBuildPluginManager.java:137)
    at org.apache.maven.lifecycle.internal.MojoExecutor.execute (MojoExecutor.java:210)
    at org.apache.maven.lifecycle.internal.MojoExecutor.execute (MojoExecutor.java:156)
    at org.apache.maven.lifecycle.internal.MojoExecutor.execute (MojoExecutor.java:148)
    at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject (LifecycleModuleBuilder.java:117)
    at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject (LifecycleModuleBuilder.java:81)
    at org.apache.maven.lifecycle.internal.builder.singlethreaded.SingleThreadedBuilder.build (SingleThreadedBuilder.java:56)
    at org.apache.maven.lifecycle.internal.LifecycleStarter.execute (LifecycleStarter.java:128)
    at org.apache.maven.DefaultMaven.doExecute (DefaultMaven.java:305)
    at org.apache.maven.DefaultMaven.doExecute (DefaultMaven.java:192)
    at org.apache.maven.DefaultMaven.execute (DefaultMaven.java:105)
    at org.apache.maven.cli.MavenCli.execute (MavenCli.java:957)
    at org.apache.maven.cli.MavenCli.doMain (MavenCli.java:289)
    at org.apache.maven.cli.MavenCli.main (MavenCli.java:193)
    at jdk.internal.reflect.NativeMethodAccessorImpl.invoke0 (Native Method)
    at jdk.internal.reflect.NativeMethodAccessorImpl.invoke (NativeMethodAccessorImpl.java:62)
    at jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke (DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke (Method.java:566)
    at org.codehaus.plexus.classworlds.launcher.Launcher.launchEnhanced (Launcher.java:282)
    at org.codehaus.plexus.classworlds.launcher.Launcher.launch (Launcher.java:225)
    at org.codehaus.plexus.classworlds.launcher.Launcher.mainWithExitCode (Launcher.java:406)
    at org.codehaus.plexus.classworlds.launcher.Launcher.main (Launcher.java:347)
    at org.codehaus.classworlds.Launcher.main (Launcher.java:47)
[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  5.669 s
[INFO] Finished at: 2022-09-26T14:35:10-04:00
[INFO] ------------------------------------------------------------------------
[ERROR] Failed to execute goal org.jsweet:jsweet-maven-plugin:3.2.0-SNAPSHOT:jsweet (generate-js) on project javacandy: transpilation failed: transpilation failed with 1 error(s) and 0 warning(s)
[ERROR] 
[ERROR] =========================================
[ERROR] TRANSPILATION ERRORS SUMMARY:
[ERROR] * a cycle was detected in static intializers involving '[D:\jsweet\javacandy\src\main\java\com\test\candies\SimpleToken.java, D:\jsweet\javacandy\src\main\java\com\test\candies\Token.java]'
...

thanks

lgrignon commented 1 year ago

Hello @tonysmarthome

Do you think this would solve this issue? I have the feeling it could.

renaudpawlak commented 1 year ago

That's an interesting one... The transpiler's dependency analyzer complains because their is a static cross-dependency between your two classes. Token statically depends on SimpleToken because it instantiates it in the TEST static field initializer. And SimpleToken statically depends on Token because it extends it. So, in a TS/JS bundle, JSweet would not know which class to define first, and that's why it complains.

In that case, I am pretty sure that JSweet is a little bit too harsh. There is supposed to be a lazy static initializers option that should allow the new SimpleToken(200, 200) initializer to be invoked lazily. Have you tried to enable it?? It might be able to work if it is on.

If it still not working (then a JSweet fix could be done to make it smarter in that case), you can overcome the issue by breaking the mutual dependency yourself. Implement the TEST initialization elsewhere, for instance by making the TEST field not final, and do Token.TEST = new SimpleToken(200, 200) in a static initializer of the SimpleToken class. Last resort, you can also simply move the TEST static field in another class such as TokenConstants.