Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 21 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,41 +8,31 @@ An sbt plugin for formatting Java code. This plugin began as a combination of id
[blog post](https://ssscripting.wordpress.com/2009/06/10/how-to-use-the-eclipse-code-formatter-from-your-code/)
and this [maven plugin](https://github.com/revelc/formatter-maven-plugin), though it has evolved since.

`google-java-format` relies on internal `jdk.compiler` APIs. On Java 17 and newer, access to those APIs is strongly encapsulated by the module system.

To keep the formatter commands working without requiring manual JVM flags, the plugin runs `google-java-format` in a forked JVM with the required module access flags.

# Usage

Add the plugin to `project/plugins.sbt`:

```scala
// Default plugin:
addSbtPlugin("com.github.sbt" % "sbt-java-formatter" % --latest version---)

// Alternative for Java 17+: wraps formatter commands in a fresh sbt JVM,
// so you do not need to configure `--add-opens` manually, see below.
addSbtPlugin("com.github.sbt" % "sbt-java-formatter-add-opens" % --latest version---)
```

For available versions see [releases](https://github.com/sbt/sbt-java-formatter/releases).

The following commands are available:

* `javafmt` formats Java files
* `javafmtAll` formats Java files for all configurations (`Compile` and `Test` by default)
* `javafmtCheck` fails if files need reformatting
* `javafmtCheckAll` fails if files need reformatting in any configuration (`Compile` and `Test` by default)

The `sbt-java-formatter-add-opens` plugin wraps the above commands and, on Java 17+, runs them in a fresh sbt JVM with the required `jdk.compiler` module access flags. From a user perspective, the commands stay the same and no manual JVM flags need to be configured.

* The `javafmtOnCompile` setting controls whether the formatter kicks in on compile (`false` by default).
* The `javafmtStyle` setting defines the formatting style: Google Java Style (by default) or AOSP style.
* The `javafmtJavaMaxHeap` setting controls the maximum heap passed to the forked `google-java-format` JVM (`Some("256m")` by default).

This plugin requires sbt 1.3.0+.

## Java 17+

`google-java-format` relies on internal `jdk.compiler` APIs. On Java 17 and newer, access to those APIs is strongly encapsulated by the module system.

If you depend on `sbt-java-formatter-add-opens`, the formatter commands (`javafmt`, `javafmtAll`, `javafmtCheck`, `javafmtCheckAll`) automatically relaunch in a JVM with the required module flags, instead of requiring manual `-J--add-opens=...` setup.

## Enable in other scopes (eg `IntegrationTest`)

The sbt plugin is enabled by default for the `Test` and `Compile` configurations. Use `JavaFormatterPlugin.toBeScopedSettings` to enable the plugin for the `IntegrationTest` scope and then use `It/javafmt` to format.
Expand All @@ -55,6 +45,22 @@ inConfig(IntegrationTest)(JavaFormatterPlugin.toBeScopedSettings)

This plugin uses the [Google Java Format](https://github.com/google/google-java-format) library, which makes it quite opinionated and not particularly configurable.

## Formatter JVM

The formatter runs in a forked JVM managed by the plugin.

Use `javafmtJavaMaxHeap` to control the maximum heap size passed to that JVM:

```scala
ThisBuild / javafmtJavaMaxHeap := Some("512m")
```

Set it to `None` to disable the explicit heap cap:

```scala
ThisBuild / javafmtJavaMaxHeap := None
```

If you want to tweak the format, take a minute to consider whether it is really worth it, and have a look at the motivations in the [Google Java Style Guide](https://google.github.io/styleguide/javaguide.html).
If you decide you really need more flexibility, you could consider other plugins such as the [sbt-checkstyle-plugin](https://github.com/etsy/sbt-checkstyle-plugin)

Expand Down
88 changes: 38 additions & 50 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -3,63 +3,51 @@ lazy val scala3 = "3.8.3"
ThisBuild / scalaVersion := scala212
ThisBuild / crossScalaVersions := Seq(scala212, scala3)

def commonSettings: Seq[Setting[?]] = Seq(
homepage := scmInfo.value.map(_.browseUrl),
scmInfo := Some(
ScmInfo(url("https://github.com/sbt/sbt-java-formatter"), "scm:git:git@github.com:sbt/sbt-java-formatter.git")),
developers := List(
Developer("ktoso", "Konrad 'ktoso' Malawski", "<ktoso@project13.pl>", url("https://github.com/ktoso"))),
startYear := Some(2015),
description := "Formats Java code in your project.",
licenses += ("Apache-2.0", url("https://www.apache.org/licenses/LICENSE-2.0.html")),
(pluginCrossBuild / sbtVersion) := {
scalaBinaryVersion.value match {
case "2.12" => "1.9.0"
case _ => "2.0.0-RC11"
}
},
scalacOptions ++= {
Vector("-encoding", "UTF-8", "-unchecked", "-deprecation", "-feature") ++ (scalaBinaryVersion.value match {
case "2.12" => Vector("-Xsource:3", "-release:11")
case _ => Vector("-Wconf:error")
})
},
javacOptions ++= Seq("-encoding", "UTF-8"),
scriptedLaunchOpts := {
scriptedLaunchOpts.value ++
Seq("-Xmx1024M", "-Dplugin.version=" + version.value)
},
scriptedLaunchOpts ++= {
if (scala.util.Properties.isJavaAtLeast("17")) {
Seq("api", "code", "file", "parser", "tree", "util").map { x =>
s"--add-exports=jdk.compiler/com.sun.tools.javac.${x}=ALL-UNNAMED"
}
} else {
Nil
}
},
scriptedBufferLog := false,
scalafmtOnCompile := !insideCI.value)

lazy val sbtJavaFormatter =
project.in(file(".")).aggregate(plugin).aggregate(`plugin-add-opens`).settings(publish / skip := true)
lazy val sbtJavaFormatter = project.in(file(".")).aggregate(plugin).settings(publish / skip := true)

lazy val plugin = project
.in(file("plugin"))
.enablePlugins(SbtPlugin)
.enablePlugins(AutomateHeaderPlugin)
.settings(commonSettings *)
.settings(
name := "sbt-java-formatter",
libraryDependencies ++= Seq("com.google.googlejavaformat" % "google-java-format" % "1.24.0"))

lazy val `plugin-add-opens` = project
.in(file("plugin-add-opens"))
.enablePlugins(SbtPlugin)
.enablePlugins(AutomateHeaderPlugin)
.settings(commonSettings *)
.settings(name := "sbt-java-formatter-add-opens")
.dependsOn(plugin)
homepage := scmInfo.value.map(_.browseUrl),
scmInfo := Some(
ScmInfo(url("https://github.com/sbt/sbt-java-formatter"), "scm:git:git@github.com:sbt/sbt-java-formatter.git")),
developers := List(
Developer("ktoso", "Konrad 'ktoso' Malawski", "<ktoso@project13.pl>", url("https://github.com/ktoso"))),
libraryDependencies ++= Seq("com.google.googlejavaformat" % "google-java-format" % "1.24.0"),
startYear := Some(2015),
description := "Formats Java code in your project.",
licenses += ("Apache-2.0", url("https://www.apache.org/licenses/LICENSE-2.0.html")),
(pluginCrossBuild / sbtVersion) := {
scalaBinaryVersion.value match {
case "2.12" => "1.9.0"
case _ => "2.0.0-RC11"
}
},
scalacOptions ++= {
Vector("-encoding", "UTF-8", "-unchecked", "-deprecation", "-feature") ++ (scalaBinaryVersion.value match {
case "2.12" => Vector("-Xsource:3", "-release:11")
case _ => Vector("-Wconf:error")
})
},
javacOptions ++= Seq("-encoding", "UTF-8"),
scriptedLaunchOpts := {
scriptedLaunchOpts.value ++
Seq("-Xmx1024M", "-Dplugin.version=" + version.value)
},
scriptedLaunchOpts ++= {
if (scala.util.Properties.isJavaAtLeast("17")) {
Seq("api", "code", "file", "parser", "tree", "util").map { x =>
s"--add-exports=jdk.compiler/com.sun.tools.javac.${x}=ALL-UNNAMED"
}
} else {
Nil
}
},
scriptedBufferLog := false,
scalafmtOnCompile := !insideCI.value)

ThisBuild / organization := "com.github.sbt"
ThisBuild / organizationName := "sbt community"

This file was deleted.

13 changes: 10 additions & 3 deletions plugin/src/main/scala/com/github/sbt/JavaFormatterPlugin.scala
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ object JavaFormatterPlugin extends AutoPlugin {
val javafmtOnCompile = settingKey[Boolean]("Format Java source files on compile, off by default.")
val javafmtStyle =
settingKey[JavaFormatterOptions.Style]("Define formatting style, Google Java Style (default) or AOSP")
val javafmtJavaMaxHeap =
settingKey[Option[String]]("Maximum heap size passed to the forked google-java-format JVM, e.g. Some(\"256m\").")
val javafmtOptions = settingKey[JavaFormatterOptions](
"Define all formatting options such as style or enabling Javadoc formatting. See _JavaFormatterOptions_ for more")
}
Expand All @@ -73,7 +75,10 @@ object JavaFormatterPlugin extends AutoPlugin {
}

override def globalSettings: Seq[Def.Setting[?]] =
Seq(javafmtOnCompile := false, javafmtStyle := JavaFormatterOptions.Style.GOOGLE)
Seq(
javafmtOnCompile := false,
javafmtStyle := JavaFormatterOptions.Style.GOOGLE,
javafmtJavaMaxHeap := Some("256m"))

def toBeScopedSettings: Seq[Setting[?]] =
List(
Expand All @@ -86,7 +91,8 @@ object JavaFormatterPlugin extends AutoPlugin {
val eF = (javafmt / excludeFilter).value
val cache = streamz.cacheStoreFactory
val options = javafmtOptions.value
JavaFormatter(sD, iF, eF, streamz, cache, options)
val javaMaxHeap = javafmtJavaMaxHeap.value
JavaFormatter(sD, iF, eF, streamz, cache, options, javaMaxHeap)
},
javafmtCheck := {
val streamz = streams.value
Expand All @@ -96,7 +102,8 @@ object JavaFormatterPlugin extends AutoPlugin {
val eF = (javafmt / excludeFilter).value
val cache = (javafmt / streams).value.cacheStoreFactory
val options = javafmtOptions.value
JavaFormatter.check(baseDir, sD, iF, eF, streamz, cache, options)
val javaMaxHeap = javafmtJavaMaxHeap.value
JavaFormatter.check(baseDir, sD, iF, eF, streamz, cache, options, javaMaxHeap)
},
javafmtDoFormatOnCompile := Def.settingDyn {
if (javafmtOnCompile.value) {
Expand Down
Loading