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

Java 17 compatibility #612

Closed
iemejia opened this issue May 31, 2021 · 21 comments
Closed

Java 17 compatibility #612

iemejia opened this issue May 31, 2021 · 21 comments

Comments

@iemejia
Copy link

iemejia commented May 31, 2021

It seems that Java 17 (next LTS) will have stricter access requirements
https://openjdk.java.net/jeps/403

I tried to run this tool and noticed this error:

Caused by: java.lang.IllegalAccessError: class com.google.googlejavaformat.java.RemoveUnusedImports (in unnamed module @0x5c25324c) cannot access class com.sun.tools.javac.util.Context (in module jdk.compiler) because module jdk.compiler does not export com.sun.tools.javac.util to unnamed module @0x5c25324c
        at com.google.googlejavaformat.java.RemoveUnusedImports.removeUnusedImports(RemoveUnusedImports.java:188)
@cushon
Copy link
Collaborator

cushon commented May 31, 2021

(in unnamed module @0x5c25324c) cannot access class com.sun.tools.javac.util.Context (in module jdk.compiler)

You'll need to add the --add-exports= flags documented here to run the formatter on JDK 16 and newer: https://github.com/google/google-java-format#jdk-16

@iemejia
Copy link
Author

iemejia commented Jun 1, 2021

I am using google-java-format via spotless so I can workaround this with --add-exports on MAVEN_OPTS as suggested also here diffplug/spotless#834

Is there a way this can be fixed out of the box for users of the library or would it require the full Java module stuff?

@cushon
Copy link
Collaborator

cushon commented Jun 2, 2021

Is there a way this can be fixed out of the box for users of the library or would it require the full Java module stuff?

I don't know any good alternatives: --add-exports= has to be passed at the top level, there isn't a supported way for a library like google-java-format to disable those access checks for all uses of the library.

@cushon cushon closed this as completed Jun 2, 2021
@iemejia
Copy link
Author

iemejia commented Jun 2, 2021

Thanks @cushon !

@fcurts
Copy link

fcurts commented Aug 10, 2021

What's the long-term solution?

  • --add-exports is meant to be used as a temporary workaround. It can break in any new Java version, at which point users of google-java-format won't be able to upgrade.
  • Depending on the build tool and environment, --add-exports can be difficult to set (it took me half a day).

@cushon
Copy link
Collaborator

cushon commented Aug 10, 2021

  • --add-exports is meant to be used as a temporary workaround. It can break in any new Java version, at which point users of google-java-format won't be able to upgrade.

--illegal-access was removed in JEP 369, but I'm not aware of any long-term plans to remove --add-exports or --add-opens

@fcurts
Copy link

fcurts commented Aug 10, 2021

I'm not aware of any long-term plans to remove --add-exports or --add-opens

Are you effectively saying that google-java-format intentionally depends on JDK internals, accepting the risk that it can break any time a new JDK version comes out?

@davidyscott
Copy link

With Java 17 GA only 6 days away, some further insight on your plans to address this issue would be greatly appreciated.

@cushon
Copy link
Collaborator

cushon commented Sep 8, 2021

The plan is to continue using --add-exports=, and to support JDK 17 and future Java versions.

JDK 17 should already work and is being tested on CI, if you see issues with it or other upcoming versions please report them.

@davidyscott
Copy link

It seems pretty unreasonable to require all users to jump through that sort of hoop.

@rmannibucau
Copy link

Any hope this bug gets fixed? JVM options are not an option in a lot of environments so we need an actual fix as other checkers did probably.

@cushon
Copy link
Collaborator

cushon commented Apr 25, 2022

As of ee81afc, the flags aren't needed when invoking the CLI using java -jar. (They are still needed when using google-java-format as a library.)

It seems pretty unreasonable to require all users to jump through that sort of hoop.

Any hope this bug gets fixed? JVM options are not an option in a lot of environments so we need an actual fix as other checkers did probably.

Are there any specific suggestions about alternatives, or fixes that were used in other checkers?

@rmannibucau
Copy link

IIRC the workarounds were to either rewrite the related code to not depends on internals of the JDK or to force the modules to be opened programmatically (something like https://github.com/openjdk/jdk/blob/5a7f22ab94bff4899b2f36ba27ea120ee7d8f1db/src/java.base/share/classes/java/lang/Module.java#L862) but I don't have all the details handy anymore. Think lombok and error prone got this issue too and solved it.

@cushon
Copy link
Collaborator

cushon commented Apr 25, 2022

rewrite the related code to not depends on internals of the JDK

It would be possible to port the formatter to a different front-end instead of using javac's parser. That would be a principled solution, but there are costs to making the switch and then maintaining a different parser or relying on something that may not get updated to support new language features as quickly as javac.

force the modules to be opened programmatically (something like https://github.com/openjdk/jdk/blob/5a7f22ab94bff4899b2f36ba27ea120ee7d8f1db/src/java.base/share/classes/java/lang/Module.java#L862)

That looks like an implementation detail of --add-opens=, do you know of a supported way to do that programmatically?

lombok and error prone got this issue too and solved it

That isn't the case for Error Prone, see the mention of --add-exports= here.

Lombok is using unsupported APIs to disable the module system encapsulation.

@rmannibucau
Copy link

@cushon I fear the supported ways will rely on JPMS API and this one will not be available in most tools except the custom launcher option. Agree lombok uses unsupported API but it works. Another option would be to force all integrators to fork but it would be quite a regression IMHO in terms of behavior so having a way to run smoothly without hacking the JVM (which has side effects on other plugins/tasks) would be great even if it requires a few more frequent release probably (one per 6 months?).

@tbroyer
Copy link
Contributor

tbroyer commented Apr 25, 2022

Agree lombok uses unsupported API but it works.

For now, and this is only temporary (see linked discussion on Lombok issue tracker)

@tisonkun
Copy link

tisonkun commented May 13, 2022

Shall we revert 3c191c1 to depend on a shaded lib and workaround this issue for library usage?

Sorry, it seems that Error Prone suffers the same problem.

@sureshg
Copy link

sureshg commented May 31, 2022

First of all sorry to comment on this closed issue. Sharing this info as I think might be useful for fixing the manual configuration. This is how kotlin solved this issue for kapt - JetBrains/kotlin@52e4506

@lazystone
Copy link

I've just tried id("com.diffplug.spotless") version "6.7.0" with googleJavaFormat("1.15.0") and still get this:

Step 'google-java-format' found problem in 'src/main/java/foo/Bar.java':
null
java.lang.reflect.InvocationTargetException
        at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:119)
        at com.diffplug.spotless.java.GoogleJavaFormatStep$State.lambda$createFormat$1(GoogleJavaFormatStep.java:177)
        at com.diffplug.spotless.FormatterFunc.apply(FormatterFunc.java:32)
        at com.diffplug.spotless.FormatterStepImpl$Standard.format(FormatterStepImpl.java:82)
        at com.diffplug.spotless.FormatterStep$Strict.format(FormatterStep.java:88)
        at com.diffplug.spotless.Formatter.compute(Formatter.java:230)
        at com.diffplug.spotless.PaddedCell.calculateDirtyState(PaddedCell.java:203)
        at com.diffplug.spotless.PaddedCell.calculateDirtyState(PaddedCell.java:190)
        at com.diffplug.gradle.spotless.SpotlessTaskImpl.processInputFile(SpotlessTaskImpl.java:92)
        at com.diffplug.gradle.spotless.SpotlessTaskImpl.performAction(SpotlessTaskImpl.java:78)
        at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104)
        at org.gradle.internal.reflect.JavaMethod.invoke(JavaMethod.java:104)
        at org.gradle.api.internal.project.taskfactory.IncrementalInputsTaskAction.doExecute(IncrementalInputsTaskAction.java:32)
        at org.gradle.api.internal.project.taskfactory.StandardTaskAction.execute(StandardTaskAction.java:51)
        at org.gradle.api.internal.project.taskfactory.AbstractIncrementalTaskAction.execute(AbstractIncrementalTaskAction.java:25)
        at org.gradle.api.internal.project.taskfactory.StandardTaskAction.execute(StandardTaskAction.java:29)
        at org.gradle.api.internal.tasks.execution.TaskExecution$3.run(TaskExecution.java:242)
        at org.gradle.internal.operations.DefaultBuildOperationRunner$1.execute(DefaultBuildOperationRunner.java:29)
        at org.gradle.internal.operations.DefaultBuildOperationRunner$1.execute(DefaultBuildOperationRunner.java:26)
        at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:66)
        at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:59)
        at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:157)
        at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:59)
        at org.gradle.internal.operations.DefaultBuildOperationRunner.run(DefaultBuildOperationRunner.java:47)
        at org.gradle.internal.operations.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:68)
        at org.gradle.api.internal.tasks.execution.TaskExecution.executeAction(TaskExecution.java:227)
        at org.gradle.api.internal.tasks.execution.TaskExecution.executeActions(TaskExecution.java:210)
        at org.gradle.api.internal.tasks.execution.TaskExecution.executeWithPreviousOutputFiles(TaskExecution.java:193)
        at org.gradle.api.internal.tasks.execution.TaskExecution.execute(TaskExecution.java:171)
        at org.gradle.internal.execution.steps.ExecuteStep.executeInternal(ExecuteStep.java:89)
        at org.gradle.internal.execution.steps.ExecuteStep.access$000(ExecuteStep.java:40)
        at org.gradle.internal.execution.steps.ExecuteStep$1.call(ExecuteStep.java:53)
        at org.gradle.internal.execution.steps.ExecuteStep$1.call(ExecuteStep.java:50)
        at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:204)
        at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:199)
        at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:66)
        at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:59)
        at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:157)
        at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:59)
        at org.gradle.internal.operations.DefaultBuildOperationRunner.call(DefaultBuildOperationRunner.java:53)
        at org.gradle.internal.operations.DefaultBuildOperationExecutor.call(DefaultBuildOperationExecutor.java:73)
        at org.gradle.internal.execution.steps.ExecuteStep.execute(ExecuteStep.java:50)
        at org.gradle.internal.execution.steps.ExecuteStep.execute(ExecuteStep.java:40)
        at org.gradle.internal.execution.steps.RemovePreviousOutputsStep.execute(RemovePreviousOutputsStep.java:68)
        at org.gradle.internal.execution.steps.RemovePreviousOutputsStep.execute(RemovePreviousOutputsStep.java:38)
        at org.gradle.internal.execution.steps.ResolveInputChangesStep.execute(ResolveInputChangesStep.java:48)
        at org.gradle.internal.execution.steps.ResolveInputChangesStep.execute(ResolveInputChangesStep.java:36)
        at org.gradle.internal.execution.steps.CancelExecutionStep.execute(CancelExecutionStep.java:41)
        at org.gradle.internal.execution.steps.TimeoutStep.executeWithoutTimeout(TimeoutStep.java:74)
        at org.gradle.internal.execution.steps.TimeoutStep.execute(TimeoutStep.java:55)
        at org.gradle.internal.execution.steps.CreateOutputsStep.execute(CreateOutputsStep.java:51)
        at org.gradle.internal.execution.steps.CreateOutputsStep.execute(CreateOutputsStep.java:29)
        at org.gradle.internal.execution.steps.CaptureStateAfterExecutionStep.execute(CaptureStateAfterExecutionStep.java:61)
        at org.gradle.internal.execution.steps.CaptureStateAfterExecutionStep.execute(CaptureStateAfterExecutionStep.java:42)
        at org.gradle.internal.execution.steps.BroadcastChangingOutputsStep.execute(BroadcastChangingOutputsStep.java:60)
        at org.gradle.internal.execution.steps.BroadcastChangingOutputsStep.execute(BroadcastChangingOutputsStep.java:27)
        at org.gradle.internal.execution.steps.BuildCacheStep.executeWithoutCache(BuildCacheStep.java:180)
        at org.gradle.internal.execution.steps.BuildCacheStep.lambda$execute$1(BuildCacheStep.java:75)
        at org.gradle.internal.Either$Right.fold(Either.java:175)
        at org.gradle.internal.execution.caching.CachingState.fold(CachingState.java:59)
        at org.gradle.internal.execution.steps.BuildCacheStep.execute(BuildCacheStep.java:73)
        at org.gradle.internal.execution.steps.BuildCacheStep.execute(BuildCacheStep.java:48)
        at org.gradle.internal.execution.steps.StoreExecutionStateStep.execute(StoreExecutionStateStep.java:36)
        at org.gradle.internal.execution.steps.StoreExecutionStateStep.execute(StoreExecutionStateStep.java:25)
        at org.gradle.internal.execution.steps.RecordOutputsStep.execute(RecordOutputsStep.java:36)
        at org.gradle.internal.execution.steps.RecordOutputsStep.execute(RecordOutputsStep.java:22)
        at org.gradle.internal.execution.steps.SkipUpToDateStep.executeBecause(SkipUpToDateStep.java:110)
        at org.gradle.internal.execution.steps.SkipUpToDateStep.lambda$execute$2(SkipUpToDateStep.java:56)
        at org.gradle.internal.execution.steps.SkipUpToDateStep.execute(SkipUpToDateStep.java:56)
        at org.gradle.internal.execution.steps.SkipUpToDateStep.execute(SkipUpToDateStep.java:38)
        at org.gradle.internal.execution.steps.ResolveChangesStep.execute(ResolveChangesStep.java:73)
        at org.gradle.internal.execution.steps.ResolveChangesStep.execute(ResolveChangesStep.java:44)
        at org.gradle.internal.execution.steps.legacy.MarkSnapshottingInputsFinishedStep.execute(MarkSnapshottingInputsFinishedStep.java:37)
        at org.gradle.internal.execution.steps.legacy.MarkSnapshottingInputsFinishedStep.execute(MarkSnapshottingInputsFinishedStep.java:27)
        at org.gradle.internal.execution.steps.ResolveCachingStateStep.execute(ResolveCachingStateStep.java:89)
        at org.gradle.internal.execution.steps.ResolveCachingStateStep.execute(ResolveCachingStateStep.java:50)
        at org.gradle.internal.execution.steps.ValidateStep.execute(ValidateStep.java:114)
        at org.gradle.internal.execution.steps.ValidateStep.execute(ValidateStep.java:57)
        at org.gradle.internal.execution.steps.CaptureStateBeforeExecutionStep.execute(CaptureStateBeforeExecutionStep.java:76)
        at org.gradle.internal.execution.steps.CaptureStateBeforeExecutionStep.execute(CaptureStateBeforeExecutionStep.java:50)
        at org.gradle.internal.execution.steps.SkipEmptyWorkStep.executeWithNoEmptySources(SkipEmptyWorkStep.java:249)
        at org.gradle.internal.execution.steps.SkipEmptyWorkStep.execute(SkipEmptyWorkStep.java:86)
        at org.gradle.internal.execution.steps.SkipEmptyWorkStep.execute(SkipEmptyWorkStep.java:54)
        at org.gradle.internal.execution.steps.RemoveUntrackedExecutionStateStep.execute(RemoveUntrackedExecutionStateStep.java:32)
        at org.gradle.internal.execution.steps.RemoveUntrackedExecutionStateStep.execute(RemoveUntrackedExecutionStateStep.java:21)
        at org.gradle.internal.execution.steps.legacy.MarkSnapshottingInputsStartedStep.execute(MarkSnapshottingInputsStartedStep.java:38)
        at org.gradle.internal.execution.steps.LoadPreviousExecutionStateStep.execute(LoadPreviousExecutionStateStep.java:43)
        at org.gradle.internal.execution.steps.LoadPreviousExecutionStateStep.execute(LoadPreviousExecutionStateStep.java:31)
        at org.gradle.internal.execution.steps.AssignWorkspaceStep.lambda$execute$0(AssignWorkspaceStep.java:40)
        at org.gradle.api.internal.tasks.execution.TaskExecution$4.withWorkspace(TaskExecution.java:287)
        at org.gradle.internal.execution.steps.AssignWorkspaceStep.execute(AssignWorkspaceStep.java:40)
        at org.gradle.internal.execution.steps.AssignWorkspaceStep.execute(AssignWorkspaceStep.java:30)
        at org.gradle.internal.execution.steps.IdentityCacheStep.execute(IdentityCacheStep.java:37)
        at org.gradle.internal.execution.steps.IdentityCacheStep.execute(IdentityCacheStep.java:27)
        at org.gradle.internal.execution.steps.IdentifyStep.execute(IdentifyStep.java:44)
        at org.gradle.internal.execution.steps.IdentifyStep.execute(IdentifyStep.java:33)
        at org.gradle.internal.execution.impl.DefaultExecutionEngine$1.execute(DefaultExecutionEngine.java:76)
        at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeIfValid(ExecuteActionsTaskExecuter.java:144)
        at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.execute(ExecuteActionsTaskExecuter.java:133)
        at org.gradle.api.internal.tasks.execution.CleanupStaleOutputsExecuter.execute(CleanupStaleOutputsExecuter.java:77)
        at org.gradle.api.internal.tasks.execution.FinalizePropertiesTaskExecuter.execute(FinalizePropertiesTaskExecuter.java:46)
        at org.gradle.api.internal.tasks.execution.ResolveTaskExecutionModeExecuter.execute(ResolveTaskExecutionModeExecuter.java:51)
        at org.gradle.api.internal.tasks.execution.SkipTaskWithNoActionsExecuter.execute(SkipTaskWithNoActionsExecuter.java:57)
        at org.gradle.api.internal.tasks.execution.SkipOnlyIfTaskExecuter.execute(SkipOnlyIfTaskExecuter.java:56)
        at org.gradle.api.internal.tasks.execution.CatchExceptionTaskExecuter.execute(CatchExceptionTaskExecuter.java:36)
        at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter$1.executeTask(EventFiringTaskExecuter.java:77)
        at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter$1.call(EventFiringTaskExecuter.java:55)
        at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter$1.call(EventFiringTaskExecuter.java:52)
        at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:204)
        at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:199)
        at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:66)
        at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:59)
        at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:157)
        at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:59)
        at org.gradle.internal.operations.DefaultBuildOperationRunner.call(DefaultBuildOperationRunner.java:53)
        at org.gradle.internal.operations.DefaultBuildOperationExecutor.call(DefaultBuildOperationExecutor.java:73)
        at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter.execute(EventFiringTaskExecuter.java:52)
        at org.gradle.execution.plan.LocalTaskNodeExecutor.execute(LocalTaskNodeExecutor.java:74)
        at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$InvokeNodeExecutorsAction.execute(DefaultTaskExecutionGraph.java:333)
        at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$InvokeNodeExecutorsAction.execute(DefaultTaskExecutionGraph.java:320)
        at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$BuildOperationAwareExecutionAction.execute(DefaultTaskExecutionGraph.java:313)
        at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$BuildOperationAwareExecutionAction.execute(DefaultTaskExecutionGraph.java:299)
        at org.gradle.execution.plan.DefaultPlanExecutor$ExecutorWorker.lambda$run$0(DefaultPlanExecutor.java:143)
        at org.gradle.execution.plan.DefaultPlanExecutor$ExecutorWorker.execute(DefaultPlanExecutor.java:227)
        at org.gradle.execution.plan.DefaultPlanExecutor$ExecutorWorker.executeNextNode(DefaultPlanExecutor.java:218)
        at org.gradle.execution.plan.DefaultPlanExecutor$ExecutorWorker.run(DefaultPlanExecutor.java:140)
        at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:64)
        at org.gradle.internal.concurrent.ManagedExecutorImpl$1.run(ManagedExecutorImpl.java:48)
Caused by: java.lang.IllegalAccessError: class com.google.googlejavaformat.java.JavaInput (in unnamed module @0x548250c8) cannot access class com.sun.tools.javac.parser.Tokens$TokenKind (in module jdk.compiler) because module jdk.compiler does not export com.sun.tools.javac.parser to unnamed module @0x548250c8
        at com.google.googlejavaformat.java.JavaInput.buildToks(JavaInput.java:349)
        at com.google.googlejavaformat.java.JavaInput.buildToks(JavaInput.java:334)
        at com.google.googlejavaformat.java.JavaInput.<init>(JavaInput.java:276)
        at com.google.googlejavaformat.java.Formatter.getFormatReplacements(Formatter.java:260)
        at com.google.googlejavaformat.java.Formatter.formatSource(Formatter.java:247)
        at com.google.googlejavaformat.java.Formatter.formatSource(Formatter.java:213)
        at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104)
        ... 127 more

@tbroyer
Copy link
Contributor

tbroyer commented Jun 5, 2022

@lazystone
Copy link

@tbroyer Ah, I just saw that PR above mentions this issue, so I thought that it's fixed.

But now docs says "This is a workaround to a diffplug/spotless#834." which is also closed...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

9 participants