-
Notifications
You must be signed in to change notification settings - Fork 90
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Java Renderers (code generators for Java only sbt projects)
- Loading branch information
Showing
10 changed files
with
566 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,208 @@ | ||
package sbtbuildinfo | ||
|
||
abstract class JavaRenderer(pkg: String, cl: String, makeStatic: Boolean) extends BuildInfoRenderer { | ||
|
||
override def fileType = BuildInfoType.Source | ||
override def extension = "java" | ||
|
||
def header = List( | ||
"// $COVERAGE-OFF$", | ||
s"package $pkg;", | ||
"", | ||
s"/** This file was generated by sbt-buildinfo. */", | ||
s"public final class $cl {", | ||
s" private $cl() {}", | ||
"" | ||
) | ||
|
||
protected def footer = List("}", "// $COVERAGE-ON$") | ||
|
||
protected def line(result: BuildInfoResult): Seq[String] = { | ||
import result._ | ||
val mod = if (makeStatic) " static" else "" | ||
getJavaType(result.typeExpr) | ||
.map(typeDecl => | ||
List( | ||
s" /** The value is ${quote(value)}. */", | ||
s" public$mod final $typeDecl $identifier = ${quote(value)};" | ||
) | ||
) | ||
.getOrElse(List.empty) | ||
} | ||
|
||
protected val buildUrlLines: String = | ||
""" private static java.net.URL internalAsUrl(String urlString) { | ||
| try { | ||
| return new java.net.URL(urlString); | ||
| } catch (Exception e) { | ||
| return null; | ||
| } | ||
| } | ||
|""".stripMargin | ||
|
||
protected val buildMapLines: String = | ||
""" @SuppressWarnings({"unchecked", "rawtypes"}) | ||
| private static <K, V> java.util.Map<K, V> internalAsMap(java.util.Map.Entry... entries) { | ||
| java.util.Map<K, V> m = new java.util.HashMap<>(); | ||
| for (java.util.Map.Entry e : entries) { | ||
| m.put((K) e.getKey(), (V) e.getValue()); | ||
| } | ||
| return java.util.Collections.unmodifiableMap(m); | ||
| } | ||
|""".stripMargin | ||
|
||
protected def toStringLines(results: Seq[BuildInfoResult]): String = { | ||
val mod = if (makeStatic) " static" else "" | ||
val methodPrefix = if (makeStatic) "make" else "to" | ||
val idents = results.filter(v => getJavaType(v.typeExpr).isDefined).map(_.identifier) | ||
val fmt = idents.map("%s: %%s" format _).mkString(", ") | ||
val vars = idents.mkString(", ") | ||
s""" | ||
| public$mod String ${methodPrefix}String() { | ||
| return String.format("$fmt", | ||
| $vars | ||
| ); | ||
| } | ||
|""".stripMargin | ||
} | ||
|
||
protected def toMapLines(results: Seq[BuildInfoResult]): Seq[String] = | ||
if (options.contains(BuildInfoOption.ToMap) || options.contains(BuildInfoOption.ToJson)) { | ||
val mod = if (makeStatic) " static" else "" | ||
val methodPrefix = if (makeStatic) "make" else "to" | ||
List( | ||
s" public$mod java.util.Map<String, Object> ${methodPrefix}Map() {", | ||
" java.util.Map<String, Object> m = new java.util.HashMap<>();" | ||
) ++ | ||
results | ||
.filter(v => getJavaType(v.typeExpr).isDefined) | ||
.map(result => " m.put(\"%s\", %s);".format(result.identifier, result.identifier)) ++ | ||
List( | ||
" return java.util.Collections.unmodifiableMap(m);", | ||
" }", | ||
"" | ||
) | ||
} else Nil | ||
|
||
protected def buildJsonLines: Seq[String] = | ||
if (options contains BuildInfoOption.ToJson) | ||
List( | ||
s""" private static String quote(Object x) { | ||
| return "\\"" + x + "\\""; | ||
| } | ||
| | ||
| @SuppressWarnings({"unchecked"}) | ||
| private static String toJsonValue(Object value) { | ||
| if (value instanceof java.util.Collection) { | ||
| return ((java.util.Collection<Object>) value) | ||
| .stream().map($cl::toJsonValue).collect(java.util.stream.Collectors.joining(",", "[", "]")); | ||
| } else if (value instanceof java.util.Optional) { | ||
| return ((java.util.Optional<Object>) value).map($cl::toJsonValue).orElse("null"); | ||
| } else if (value instanceof java.util.Map) { | ||
| return ((java.util.Map<Object, Object>) value) | ||
| .entrySet().stream() | ||
| .map(e -> toJsonValue(e.getKey().toString()) + ":" + toJsonValue(e.getValue())) | ||
| .collect(java.util.stream.Collectors.joining(", ", "{", "}")); | ||
| } else if (value instanceof Double) { | ||
| return value.toString(); | ||
| } else if (value instanceof Float) { | ||
| return value.toString(); | ||
| } else if (value instanceof Long) { | ||
| return value.toString(); | ||
| } else if (value instanceof Integer) { | ||
| return value.toString(); | ||
| } else if (value instanceof Short) { | ||
| return value.toString(); | ||
| } else if (value instanceof Boolean) { | ||
| return value.toString(); | ||
| } else if (value instanceof String) { | ||
| return quote(value); | ||
| } else { | ||
| return quote(value.toString()); | ||
| } | ||
| } | ||
|""".stripMargin | ||
) | ||
else | ||
Nil | ||
|
||
protected def toJsonLines: Seq[String] = | ||
if (options contains BuildInfoOption.ToJson) { | ||
val mod = if (makeStatic) " static" else "" | ||
val methodPrefix = if (makeStatic) "make" else "to" | ||
List( | ||
s""" public$mod final String ${methodPrefix}Json = toJsonValue(${methodPrefix}Map());""".stripMargin | ||
) | ||
} else | ||
Nil | ||
|
||
protected def getJavaType(typeExpr: TypeExpression): Option[String] = { | ||
def tpeToReturnType(tpe: TypeExpression): Option[String] = | ||
tpe match { | ||
case TypeExpression("Any", Nil) => None | ||
case TypeExpression("Short", Nil) => Some("Short") | ||
case TypeExpression("Int", Nil) => Some("Integer") | ||
case TypeExpression("Long", Nil) => Some("Long") | ||
case TypeExpression("Double", Nil) => Some("Double") | ||
case TypeExpression("Float", Nil) => Some("Float") | ||
case TypeExpression("Boolean", Nil) => Some("Boolean") | ||
case TypeExpression("scala.Symbol", Nil) => Some("String") | ||
case TypeExpression("java.lang.String", Nil) => Some("String") | ||
case TypeExpression("java.net.URL", Nil) => Some("java.net.URL") | ||
case TypeExpression("sbt.URL", Nil) => Some("java.net.URL") | ||
case TypeExpression("java.io.File", Nil) => Some("java.io.File") | ||
case TypeExpression("sbt.File", Nil) => Some("java.io.File") | ||
case TypeExpression("scala.xml.NodeSeq", Nil) => None | ||
|
||
case TypeExpression("sbt.ModuleID", Nil) => Some("String") | ||
case TypeExpression("sbt.Resolver", Nil) => Some("String") | ||
|
||
case TypeExpression("sbt.librarymanagement.ModuleID", Nil) => Some("String") | ||
case TypeExpression("sbt.librarymanagement.Resolver", Nil) => Some("String") | ||
|
||
case TypeExpression("sbt.internal.util.Attributed", Seq(TypeExpression("java.io.File", Nil))) => | ||
Some("java.io.File") | ||
|
||
case TypeExpression("scala.Option", Seq(arg)) => | ||
tpeToReturnType(arg) map { x => s"java.util.Optional<$x>" } | ||
case TypeExpression("scala.collection.Seq" | "scala.collection.immutable.Seq", Seq(arg)) => | ||
tpeToReturnType(arg) map { x => s"java.util.Collection<$x>" } | ||
case TypeExpression("scala.collection.immutable.Map", Seq(arg0, arg1)) => | ||
for { | ||
x0 <- tpeToReturnType(arg0) | ||
x1 <- tpeToReturnType(arg1) | ||
} yield s"java.util.Map<$x0, $x1>" | ||
case TypeExpression("scala.Tuple2", Seq(arg0, arg1)) => | ||
for { | ||
x0 <- tpeToReturnType(arg0) | ||
x1 <- tpeToReturnType(arg1) | ||
} yield s"java.util.Map.Entry<$x0, $x1>" | ||
case _ => None | ||
} | ||
tpeToReturnType(typeExpr) | ||
} | ||
|
||
protected def quote(v: Any): String = v match { | ||
case x @ (_: Int | _: Short | _: Double | _: Boolean) => x.toString | ||
case x: Float => x.toString + "f" | ||
case x: Symbol => s"""("${x.name}").intern()""" | ||
case x: Long => x.toString + "L" | ||
case node: scala.xml.NodeSeq if node.toString().trim.nonEmpty => node.toString() | ||
case node: scala.xml.NodeSeq => scala.xml.NodeSeq.Empty.toString() | ||
case (k, _v) => "new java.util.AbstractMap.SimpleImmutableEntry<>(%s, %s)" format (quote(k), quote(_v)) | ||
case mp: Map[_, _] => mp.toList.map(quote(_)).mkString("internalAsMap(", ", ", ")") | ||
case seq: collection.Seq[_] => | ||
seq.map(quote).mkString("java.util.Collections.unmodifiableList(java.util.Arrays.asList(", ", ", "))") | ||
case op: Option[_] => | ||
op map { x => "java.util.Optional.of(" + quote(x) + ")" } getOrElse { "java.util.Optional.empty()" } | ||
case url: java.net.URL => "internalAsUrl(%s)" format quote(url.toString) | ||
case file: java.io.File => "new java.io.File(%s)" format quote(file.toString) | ||
case attr: sbt.Attributed[_] => quote(attr.data) | ||
case s => "\"%s\"" format encodeStringLiteral(s.toString) | ||
} | ||
|
||
protected def encodeStringLiteral(str: String): String = | ||
str.replace("\\", "\\\\").replace("\n", "\\n").replace("\b", "\\b").replace("\r", "\\r") | ||
.replace("\t", "\\t").replace("\'", "\\'").replace("\f", "\\f").replace("\"", "\\\"") | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
package sbtbuildinfo | ||
|
||
case class JavaSingletonRenderer(options: Seq[BuildInfoOption], pkg: String, cl: String) extends JavaRenderer(pkg, cl, false) { | ||
|
||
override def renderKeys(buildInfoResults: Seq[BuildInfoResult]): Seq[String] = | ||
header ++ | ||
instanceLine ++ | ||
buildInfoResults.flatMap(line) ++ | ||
Seq(toStringLines(buildInfoResults)) ++ | ||
toMapLines(buildInfoResults) ++ | ||
Seq(buildUrlLines, buildMapLines) ++ | ||
buildJsonLines ++ | ||
toJsonLines ++ | ||
footer | ||
|
||
private def instanceLine: Seq[String] = | ||
List( | ||
s" public static final $cl instance = new $cl();", | ||
"" | ||
) | ||
|
||
} |
15 changes: 15 additions & 0 deletions
15
src/main/scala/sbtbuildinfo/JavaStaticFieldsRenderer.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
package sbtbuildinfo | ||
|
||
case class JavaStaticFieldsRenderer(options: Seq[BuildInfoOption], pkg: String, cl: String) extends JavaRenderer(pkg, cl, true) { | ||
|
||
override def renderKeys(buildInfoResults: Seq[BuildInfoResult]): Seq[String] = | ||
header ++ | ||
buildInfoResults.flatMap(line) ++ | ||
Seq(toStringLines(buildInfoResults)) ++ | ||
toMapLines(buildInfoResults) ++ | ||
Seq(buildUrlLines, buildMapLines) ++ | ||
buildJsonLines ++ | ||
toJsonLines ++ | ||
footer | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.