Commit b2e75f1a authored by Miro Knejp's avatar Miro Knejp Committed by Jacob Potter

Introduce marshalling object for Java code generator

parent c5dccab3
...@@ -27,6 +27,7 @@ import scala.collection.mutable ...@@ -27,6 +27,7 @@ import scala.collection.mutable
class JavaGenerator(spec: Spec) extends Generator(spec) { class JavaGenerator(spec: Spec) extends Generator(spec) {
var javaAnnotationHeader = spec.javaAnnotation.map(pkg => '@' + pkg.split("\\.").last) var javaAnnotationHeader = spec.javaAnnotation.map(pkg => '@' + pkg.split("\\.").last)
val marshal = new JavaMarshal(spec)
class JavaRefs() { class JavaRefs() {
var java = mutable.TreeSet[String]() var java = mutable.TreeSet[String]()
...@@ -76,16 +77,13 @@ class JavaGenerator(spec: Spec) extends Generator(spec) { ...@@ -76,16 +77,13 @@ class JavaGenerator(spec: Spec) extends Generator(spec) {
case d: Double => w.w(d.toString) case d: Double => w.w(d.toString)
case b: Boolean => w.w(if (b) "true" else "false") case b: Boolean => w.w(if (b) "true" else "false")
case s: String => w.w(s) case s: String => w.w(s)
case e: EnumValue => { case e: EnumValue => w.w(s"${marshal.typename(ty)}.${idJava.enum(e)}")
val enumMdef = ty.resolved.base.asInstanceOf[MDef]
w.w(s"${idJava.ty(enumMdef.name)}.${idJava.enum(e)}")
}
case v: ConstRef => w.w(idJava.const(v)) case v: ConstRef => w.w(idJava.const(v))
case z: Map[_, _] => { // Value is record case z: Map[_, _] => { // Value is record
val recordMdef = ty.resolved.base.asInstanceOf[MDef] val recordMdef = ty.resolved.base.asInstanceOf[MDef]
val record = recordMdef.body.asInstanceOf[Record] val record = recordMdef.body.asInstanceOf[Record]
val vMap = z.asInstanceOf[Map[String, Any]] val vMap = z.asInstanceOf[Map[String, Any]]
w.wl(s"new ${idJava.ty(recordMdef.name)}(") w.wl(s"new ${marshal.typename(ty)}(")
w.increase() w.increase()
// Use exact sequence // Use exact sequence
val skipFirst = SkipFirst() val skipFirst = SkipFirst()
...@@ -102,7 +100,7 @@ class JavaGenerator(spec: Spec) extends Generator(spec) { ...@@ -102,7 +100,7 @@ class JavaGenerator(spec: Spec) extends Generator(spec) {
for (c <- consts) { for (c <- consts) {
writeDoc(w, c.doc) writeDoc(w, c.doc)
javaAnnotationHeader.foreach(w.wl) javaAnnotationHeader.foreach(w.wl)
w.w(s"public static final ${toJavaType(c.ty)} ${idJava.const(c.ident)} = ") w.w(s"public static final ${marshal.typename(c.ty)} ${idJava.const(c.ident)} = ")
writeJavaConst(w, c.ty, c.value) writeJavaConst(w, c.ty, c.value)
w.wl(";") w.wl(";")
w.wl w.wl
...@@ -115,7 +113,7 @@ class JavaGenerator(spec: Spec) extends Generator(spec) { ...@@ -115,7 +113,7 @@ class JavaGenerator(spec: Spec) extends Generator(spec) {
writeJavaFile(ident, origin, refs.java, w => { writeJavaFile(ident, origin, refs.java, w => {
writeDoc(w, doc) writeDoc(w, doc)
javaAnnotationHeader.foreach(w.wl) javaAnnotationHeader.foreach(w.wl)
w.w(s"public enum ${idJava.ty(ident)}").braced { w.w(s"public enum ${marshal.typename(ident, e)}").braced {
for (o <- e.options) { for (o <- e.options) {
writeDoc(w, o.doc) writeDoc(w, o.doc)
w.wl(idJava.enum(o.ident) + ",") w.wl(idJava.enum(o.ident) + ",")
...@@ -140,7 +138,7 @@ class JavaGenerator(spec: Spec) extends Generator(spec) { ...@@ -140,7 +138,7 @@ class JavaGenerator(spec: Spec) extends Generator(spec) {
} }
writeJavaFile(ident, origin, refs.java, w => { writeJavaFile(ident, origin, refs.java, w => {
val javaClass = idJava.ty(ident) val javaClass = marshal.typename(ident, i)
val typeParamList = javaTypeParams(typeParams) val typeParamList = javaTypeParams(typeParams)
writeDoc(w, doc) writeDoc(w, doc)
...@@ -153,15 +151,15 @@ class JavaGenerator(spec: Spec) extends Generator(spec) { ...@@ -153,15 +151,15 @@ class JavaGenerator(spec: Spec) extends Generator(spec) {
for (m <- i.methods if !m.static) { for (m <- i.methods if !m.static) {
skipFirst { w.wl } skipFirst { w.wl }
writeDoc(w, m.doc) writeDoc(w, m.doc)
val ret = m.ret.fold("void")(toJavaType(_)) val ret = m.ret.fold("void")(marshal.typename(_))
val params = m.params.map(p => toJavaType(p.ty) + " " + idJava.local(p.ident)) val params = m.params.map(p => marshal.typename(p.ty) + " " + idJava.local(p.ident))
w.wl("public abstract " + ret + " " + idJava.method(m.ident) + params.mkString("(", ", ", ")") + throwException + ";") w.wl("public abstract " + ret + " " + idJava.method(m.ident) + params.mkString("(", ", ", ")") + throwException + ";")
} }
for (m <- i.methods if m.static) { for (m <- i.methods if m.static) {
skipFirst { w.wl } skipFirst { w.wl }
writeDoc(w, m.doc) writeDoc(w, m.doc)
val ret = m.ret.fold("void")(toJavaType(_)) val ret = m.ret.fold("void")(marshal.typename(_))
val params = m.params.map(p => toJavaType(p.ty) + " " + idJava.local(p.ident)) val params = m.params.map(p => marshal.typename(p.ty) + " " + idJava.local(p.ident))
w.wl("public static native "+ ret + " " + idJava.method(m.ident) + params.mkString("(", ", ", ")") + ";") w.wl("public static native "+ ret + " " + idJava.method(m.ident) + params.mkString("(", ", ", ")") + ";")
} }
if (i.ext.cpp) { if (i.ext.cpp) {
...@@ -186,9 +184,9 @@ class JavaGenerator(spec: Spec) extends Generator(spec) { ...@@ -186,9 +184,9 @@ class JavaGenerator(spec: Spec) extends Generator(spec) {
w.wl("super.finalize();") w.wl("super.finalize();")
} }
for (m <- i.methods if !m.static) { // Static methods not in CppProxy for (m <- i.methods if !m.static) { // Static methods not in CppProxy
val ret = m.ret.fold("void")(toJavaType(_)) val ret = m.ret.fold("void")(marshal.typename(_))
val returnStmt = m.ret.fold("")(_ => "return ") val returnStmt = m.ret.fold("")(_ => "return ")
val params = m.params.map(p => toJavaType(p.ty)+" "+idJava.local(p.ident)).mkString(", ") val params = m.params.map(p => marshal.typename(p.ty)+" "+idJava.local(p.ident)).mkString(", ")
val args = m.params.map(p => idJava.local(p.ident)).mkString(", ") val args = m.params.map(p => idJava.local(p.ident)).mkString(", ")
val meth = idJava.method(m.ident) val meth = idJava.method(m.ident)
w.wl w.wl
...@@ -213,34 +211,35 @@ class JavaGenerator(spec: Spec) extends Generator(spec) { ...@@ -213,34 +211,35 @@ class JavaGenerator(spec: Spec) extends Generator(spec) {
writeJavaFile(javaName, origin, refs.java, w => { writeJavaFile(javaName, origin, refs.java, w => {
writeDoc(w, doc) writeDoc(w, doc)
javaAnnotationHeader.foreach(w.wl) javaAnnotationHeader.foreach(w.wl)
val self = marshal.typename(javaName, r)
// HACK: Use generic base class to correctly implement Comparable interface // HACK: Use generic base class to correctly implement Comparable interface
val comparableFlag = val comparableFlag =
if (r.derivingTypes.contains(DerivingType.Ord)) { if (r.derivingTypes.contains(DerivingType.Ord)) {
if (r.ext.java) { if (r.ext.java) {
s"<E extends ${idJava.ty(javaName)}> implements Comparable<E>" s"<E extends $self> implements Comparable<E>"
} else { } else {
s" implements Comparable<${idJava.ty(javaName)}>" s" implements Comparable<$self>"
} }
} else { } else {
"" ""
} }
w.w(s"public$javaFinal class ${idJava.ty(javaName) + javaTypeParams(params)}$comparableFlag").braced { w.w(s"public$javaFinal class ${self + javaTypeParams(params)}$comparableFlag").braced {
w.wl w.wl
generateJavaConstants(w, r.consts) generateJavaConstants(w, r.consts)
// Field definitions. // Field definitions.
for (f <- r.fields) { for (f <- r.fields) {
w.wl w.wl
w.wl(s"/*package*/ final ${toJavaType(f.ty)} ${idJava.field(f.ident)};") w.wl(s"/*package*/ final ${marshal.typename(f.ty)} ${idJava.field(f.ident)};")
} }
// Constructor. // Constructor.
w.wl w.wl
w.wl(s"public ${idJava.ty(javaName)}(").nestedN(2) { w.wl(s"public $self(").nestedN(2) {
val skipFirst = SkipFirst() val skipFirst = SkipFirst()
for (f <- r.fields) { for (f <- r.fields) {
skipFirst { w.wl(",") } skipFirst { w.wl(",") }
w.w(toJavaType(f.ty) + " " + idJava.local(f.ident)) w.w(marshal.typename(f.ty) + " " + idJava.local(f.ident))
} }
w.wl(") {") w.wl(") {")
} }
...@@ -255,7 +254,7 @@ class JavaGenerator(spec: Spec) extends Generator(spec) { ...@@ -255,7 +254,7 @@ class JavaGenerator(spec: Spec) extends Generator(spec) {
for (f <- r.fields) { for (f <- r.fields) {
w.wl w.wl
writeDoc(w, f.doc) writeDoc(w, f.doc)
w.w("public " + toJavaType(f.ty) + " " + idJava.method("get_" + f.ident.name) + "()").braced { w.w("public " + marshal.typename(f.ty) + " " + idJava.method("get_" + f.ident.name) + "()").braced {
w.wl("return " + idJava.field(f.ident) + ";") w.wl("return " + idJava.field(f.ident) + ";")
} }
} }
...@@ -264,10 +263,10 @@ class JavaGenerator(spec: Spec) extends Generator(spec) { ...@@ -264,10 +263,10 @@ class JavaGenerator(spec: Spec) extends Generator(spec) {
w.wl w.wl
w.wl("@Override") w.wl("@Override")
w.w("public boolean equals(Object obj)").braced { w.w("public boolean equals(Object obj)").braced {
w.w(s"if (!(obj instanceof ${idJava.ty(javaName)}))").braced { w.w(s"if (!(obj instanceof $self))").braced {
w.wl("return false;"); w.wl("return false;");
} }
w.wl(s"${idJava.ty(javaName)} other = (${idJava.ty(javaName)}) obj;") w.wl(s"$self other = ($self) obj;")
w.w(s"return ").nestedN(2) { w.w(s"return ").nestedN(2) {
val skipFirst = SkipFirst() val skipFirst = SkipFirst()
for (f <- r.fields) { for (f <- r.fields) {
...@@ -296,7 +295,7 @@ class JavaGenerator(spec: Spec) extends Generator(spec) { ...@@ -296,7 +295,7 @@ class JavaGenerator(spec: Spec) extends Generator(spec) {
if (r.derivingTypes.contains(DerivingType.Ord)) { if (r.derivingTypes.contains(DerivingType.Ord)) {
w.wl w.wl
w.wl("@Override") w.wl("@Override")
val tyName = if (r.ext.java) "E" else idJava.ty(javaName) val tyName = if (r.ext.java) "E" else self
w.w(s"public int compareTo($tyName other) ").braced { w.w(s"public int compareTo($tyName other) ").braced {
w.wl("int tempResult;") w.wl("int tempResult;")
for (f <- r.fields) { for (f <- r.fields) {
...@@ -332,39 +331,6 @@ class JavaGenerator(spec: Spec) extends Generator(spec) { ...@@ -332,39 +331,6 @@ class JavaGenerator(spec: Spec) extends Generator(spec) {
}) })
} }
def toJavaType(ty: TypeRef, packageName: Option[String] = None): String = toJavaType(ty.resolved, packageName)
def toJavaType(tm: MExpr, packageName: Option[String]): String = {
def f(tm: MExpr, needRef: Boolean): String = {
tm.base match {
case MOptional =>
// HACK: We use "null" for the empty optional in Java.
assert(tm.args.size == 1)
val arg = tm.args.head
arg.base match {
case p: MPrimitive => p.jBoxed
case MOptional => throw new AssertionError("nested optional?")
case m => f(arg, true)
}
case o =>
val args = if (tm.args.isEmpty) "" else tm.args.map(f(_, true)).mkString("<", ", ", ">")
val base = o match {
case p: MPrimitive => if (needRef) p.jBoxed else p.jName
case MString => "String"
case MDate => "Date"
case MBinary => "byte[]"
case MOptional => throw new AssertionError("optional should have been special cased")
case MList => "ArrayList"
case MSet => "HashSet"
case MMap => "HashMap"
case d: MDef => withPackage(packageName, idJava.ty(d.name))
case p: MParam => idJava.typeParam(p.name)
}
base + args
}
}
f(tm, false)
}
def javaTypeParams(params: Seq[TypeParam]): String = def javaTypeParams(params: Seq[TypeParam]): String =
if (params.isEmpty) "" else params.map(p => idJava.typeParam(p.ident)).mkString("<", ", ", ">") if (params.isEmpty) "" else params.map(p => idJava.typeParam(p.ident)).mkString("<", ", ", ">")
......
package djinni
import djinni.ast._
import djinni.generatorTools._
import djinni.meta._
class JavaMarshal(spec: Spec) extends Marshal(spec) {
def typename(tm: MExpr): String = toJavaType(tm, None)
def typename(name: String, ty: TypeDef): String = idJava.ty(name)
def fqTypename(tm: MExpr): String = toJavaType(tm, spec.javaPackage)
def fqTypename(name: String, ty: TypeDef): String = withPackage(spec.javaPackage, idJava.ty(name))
def toJavaType(tm: MExpr, packageName: Option[String]): String = {
def f(tm: MExpr, needRef: Boolean): String = {
tm.base match {
case MOptional =>
// HACK: We use "null" for the empty optional in Java.
assert(tm.args.size == 1)
val arg = tm.args.head
arg.base match {
case p: MPrimitive => p.jBoxed
case MOptional => throw new AssertionError("nested optional?")
case m => f(arg, true)
}
case o =>
val args = if (tm.args.isEmpty) "" else tm.args.map(f(_, true)).mkString("<", ", ", ">")
val base = o match {
case p: MPrimitive => if (needRef) p.jBoxed else p.jName
case MString => "String"
case MDate => "Date"
case MBinary => "byte[]"
case MOptional => throw new AssertionError("optional should have been special cased")
case MList => "ArrayList"
case MSet => "HashSet"
case MMap => "HashMap"
case d: MDef => withPackage(packageName, idJava.ty(d.name))
case p: MParam => idJava.typeParam(p.name)
}
base + args
}
}
f(tm, false)
}
def withPackage(packageName: Option[String], t: String) = packageName.fold(t)(_+"."+t)
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment