{"action":"created","comment":{"url":"https://api.github.com/repos/sbt/sbt-datatype/pulls/comments/35728448","id":35728448,"diff_hunk":"@@ -0,0 +1,214 @@\n+package sbt.datatype\n+import scala.compat.Platform.EOL\n+import java.io.File\n+\n+/**\n+ * Code generator for Java.\n+ */\n+object JavaCodeGen extends CodeGenerator {\n+\n+  /** Indentation configuration for Java sources. */\n+  implicit object indentationConfiguration extends IndentationConfiguration {\n+    override val indentElement = \"    \"\n+    override def augmentIndentAfterTrigger(s: String) = s endsWith \"{\"\n+    override def reduceIndentTrigger(s: String) = s startsWith \"}\"\n+  }\n+\n+  override def generate(s: Schema): Map[File, String] =\n+    s.definitions flatMap (generate(_, None, Nil) mapValues (_.indented)) toMap\n+\n+  override def generate(p: Protocol, parent: Option[Protocol], superFields: List[Field]): Map[File, String] = {\n+    val Protocol(name, _, namespace, doc, fields, children) = p\n+    val extendsCode = parent map (p => s\"extends ${fullyQualifiedName(p)}\") getOrElse \"\"\n+\n+    val code =\n+      s\"\"\"${genPackage(p)}\n+         |${genDoc(doc)}\n+         |public abstract class $name $extendsCode {\n+         |    ${genFields(fields)}\n+         |    ${genConstructors(p, parent, superFields)}\n+         |    ${genAccessors(fields)}\n+         |    ${genEquals(p, superFields)}\n+         |    ${genHashCode(p, superFields)}\n+         |    ${genToString(p, superFields)}\n+         |}\"\"\".stripMargin\n+\n+    Map(genFile(p) -> code) ++ (children flatMap (generate(_, Some(p), superFields ++ fields)))\n+  }\n+\n+  override def generate(r: Record, parent: Option[Protocol], superFields: List[Field]): Map[File, String] = {\n+    val Record(name, _, namespace, doc, fields) = r\n+    val extendsCode = parent map (p => s\"extends ${fullyQualifiedName(p)}\") getOrElse \"\"\n+\n+    val code =\n+      s\"\"\"${genPackage(r)}\n+         |${genDoc(doc)}\n+         |public final class $name $extendsCode {\n+         |    ${genFields(fields)}\n+         |    ${genConstructors(r, parent, superFields)}\n+         |    ${genAccessors(fields)}\n+         |    ${genEquals(r, superFields)}\n+         |    ${genHashCode(r, superFields)}\n+         |    ${genToString(r, superFields)}\n+         |}\"\"\".stripMargin\n+\n+    Map(genFile(r) -> code)\n+  }\n+\n+  override def generate(e: Enumeration): Map[File, String] = {\n+    val Enumeration(name, _, namespace, doc, values) = e\n+\n+    val valuesCode = values map { case EnumerationValue(name, doc) =>\n+      s\"\"\"${genDoc(doc)}\n+         |$name\"\"\".stripMargin\n+    } mkString (\",\" + EOL)\n+\n+    val code =\n+      s\"\"\"${genPackage(e)}\n+         |${genDoc(doc)}\n+         |public enum $name {\n+         |    $valuesCode\n+         |}\"\"\".stripMargin\n+\n+    Map(genFile(e) -> code)\n+  }\n+\n+  private def genDoc(doc: Option[String]) = doc map (d => s\"/** $d */\") getOrElse \"\"\n+\n+  private def genFile(d: Definition) = {\n+    val fileName = d.name + \".java\"\n+    d.namespace map (ns => new File(ns.replace(\".\", File.separator), fileName)) getOrElse new File(fileName)\n+  }\n+\n+  private def genFields(fields: List[Field]) = fields map genField mkString EOL\n+  private def genField(f: Field) =\n+    s\"\"\"${genDoc(f.doc)}\n+       |private ${genRealTpe(f.tpe)} ${f.name};\"\"\".stripMargin\n+\n+  def isPrimitive(tpe: TpeRef) = !tpe.repeated && ! tpe.lzy && tpe.name != boxedType(tpe.name)\n+\n+  private def boxedType(tpe: String): String = tpe match {\n+    case \"boolean\" => \"Boolean\"\n+    case \"byte\"    => \"Byte\"\n+    case \"char\"    => \"Character\"\n+    case \"float\"   => \"Float\"\n+    case \"int\"     => \"Integer\"\n+    case \"long\"    => \"Long\"\n+    case \"short\"   => \"Short\"\n+    case \"double\"  => \"Double\"\n+    case other     => other\n+  }\n+\n+  private def genRealTpe(tpe: TpeRef): String = tpe match {\n+    case TpeRef(name, true, true)   => s\"Lazy<$name[]>\"\n+    case TpeRef(name, true, false)  => s\"Lazy<${boxedType(name)}>\"\n+    case TpeRef(name, false, true)  => s\"$name[]\"\n+    case TpeRef(name, false, false) => name\n+  }\n+\n+  private def genAccessors(fields: List[Field]) = fields map genAccessor mkString EOL\n+  private def genAccessor(field: Field) = {\n+    val accessCode =\n+      if (field.tpe.lzy) s\"this.${field.name}.get()\"\n+      else s\"this.${field.name}\"\n+\n+    // We don't use `genRealTpe` here because the field will be evaluated\n+    // if it is lazy.\n+    val tpeSig =\n+      if (field.tpe.repeated) s\"${field.tpe.name}[]\"\n+      else field.tpe.name\n+\n+    s\"\"\"public $tpeSig ${field.name}() {\n+       |    return $accessCode;\n+       |}\"\"\".stripMargin\n+  }\n+\n+  private def genConstructors(cl: ClassLike, parent: Option[Protocol], superFields: List[Field]) =\n+    perVersionNumber(superFields ++ cl.fields) { (provided, byDefault) =>\n+      val ctorParameters = provided map (f => s\"${genRealTpe(f.tpe)} _${f.name}\") mkString \", \"\n+      val superFieldsValues = superFields map {\n+        case f if provided contains f  => s\"_${f.name}\"\n+        case f if byDefault contains f => f.default getOrElse sys.error(s\"Need a default value for field ${f.name}.\")\n+      }\n+      val superCall = superFieldsValues.mkString(\"super(\", \", \", \");\")\n+      val assignments = cl.fields map {\n+        case f if provided contains f  => s\"${f.name} = _${f.name};\"\n+        case f if byDefault contains f => f.default map (d => s\"${f.name} = $d;\") getOrElse sys.error(s\"Need a default value for field ${f.name}.\")\n+      } mkString EOL\n+\n+      s\"\"\"public ${cl.name}($ctorParameters) {\n+         |    $superCall\n+         |    $assignments\n+         |}\"\"\".stripMargin\n+    } mkString (EOL + EOL)\n+\n+  private def genEquals(cl: ClassLike, superFields: List[Field]) = {\n+    val allFields = superFields ++ cl.fields\n+    val body =\n+      if (allFields exists (_.tpe.lzy)) {\n+        \"return this == obj; // We have lazy members, so use object identity to avoid circularity.\"","path":"library/src/main/scala/JavaCodeGen.scala","position":149,"original_position":149,"commit_id":"88d98979f6a3a4d1ec4cae7537af4dfb4f0c55df","original_commit_id":"88d98979f6a3a4d1ec4cae7537af4dfb4f0c55df","user":{"login":"eed3si9n","id":184683,"avatar_url":"https://avatars.githubusercontent.com/u/184683?v=3","gravatar_id":"","url":"https://api.github.com/users/eed3si9n","html_url":"https://github.com/eed3si9n","followers_url":"https://api.github.com/users/eed3si9n/followers","following_url":"https://api.github.com/users/eed3si9n/following{/other_user}","gists_url":"https://api.github.com/users/eed3si9n/gists{/gist_id}","starred_url":"https://api.github.com/users/eed3si9n/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/eed3si9n/subscriptions","organizations_url":"https://api.github.com/users/eed3si9n/orgs","repos_url":"https://api.github.com/users/eed3si9n/repos","events_url":"https://api.github.com/users/eed3si9n/events{/privacy}","received_events_url":"https://api.github.com/users/eed3si9n/received_events","type":"User","site_admin":false},"body":"Is this true? We can't check equality for an object that contains a lazy field?","created_at":"2015-07-29T05:18:41Z","updated_at":"2015-07-29T05:18:41Z","html_url":"https://github.com/sbt/sbt-datatype/pull/2#discussion_r35728448","pull_request_url":"https://api.github.com/repos/sbt/sbt-datatype/pulls/2","_links":{"self":{"href":"https://api.github.com/repos/sbt/sbt-datatype/pulls/comments/35728448"},"html":{"href":"https://github.com/sbt/sbt-datatype/pull/2#discussion_r35728448"},"pull_request":{"href":"https://api.github.com/repos/sbt/sbt-datatype/pulls/2"}}},"pull_request":{"url":"https://api.github.com/repos/sbt/sbt-datatype/pulls/2","id":40773829,"html_url":"https://github.com/sbt/sbt-datatype/pull/2","diff_url":"https://github.com/sbt/sbt-datatype/pull/2.diff","patch_url":"https://github.com/sbt/sbt-datatype/pull/2.patch","issue_url":"https://api.github.com/repos/sbt/sbt-datatype/issues/2","number":2,"state":"open","locked":false,"title":"New schema, new code generators for Scala and Java, sbt plugin","user":{"login":"Duhemm","id":1765926,"avatar_url":"https://avatars.githubusercontent.com/u/1765926?v=3","gravatar_id":"","url":"https://api.github.com/users/Duhemm","html_url":"https://github.com/Duhemm","followers_url":"https://api.github.com/users/Duhemm/followers","following_url":"https://api.github.com/users/Duhemm/following{/other_user}","gists_url":"https://api.github.com/users/Duhemm/gists{/gist_id}","starred_url":"https://api.github.com/users/Duhemm/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Duhemm/subscriptions","organizations_url":"https://api.github.com/users/Duhemm/orgs","repos_url":"https://api.github.com/users/Duhemm/repos","events_url":"https://api.github.com/users/Duhemm/events{/privacy}","received_events_url":"https://api.github.com/users/Duhemm/received_events","type":"User","site_admin":false},"body":"### Changes to the schema\r\n\r\n - The definition of a `protocol`, `record` or `enumeration` must include the target language (Scala or Java) and optionally its namespace.\r\n```javascript\r\n{\r\n\t\"name\": \"Greetings\",\r\n\t\"target\": \"Scala\",\r\n\t\"namespace\": \"com.example\",\r\n\t\"type\": \"protocol\",\r\n\t\"doc\": \"Protocol Greetings\"\r\n}\r\n```\r\n\r\n - Subtypes of a `protocol` must be defined within the `protocol`:\r\n```javascript\r\n{\r\n\t\"name\": \"Greetings\",\r\n\t\"target\": \"Scala\",\r\n\t\"type\": \"protocol\",\r\n\t\"doc\": \"Protocol Greetings\",\r\n\r\n\t\"types\": [\r\n\t\t{\r\n\t\t\t\"name\": \"NamedGreetings\",\r\n\t\t\t\"type\": \"record\",\r\n\t\t\t...\r\n\t\t},\r\n\t\t{\r\n\t\t\t\"name\": \"AnonymousGreetings\",\r\n\t\t\t\"type\": \"record\",\r\n\t\t\t...\r\n\t\t}\r\n\t]\r\n}\r\n```\r\n - `protocol`s can be defined inside `protocol`s\r\n```javascript\r\n{\r\n\t\"name\": \"Greetings\",\r\n\t\"target\": \"Scala\",\r\n\t\"type\": \"protocol\",\r\n\t\"doc\": \"Protocol Greetings\",\r\n\r\n\t\"types\": [\r\n\t\t{\r\n\t\t\t\"name\": \"RemoteGreeting\",\r\n\t\t\t\"target\": \"Scala\",\r\n\t\t\t\"type\": \"Protocol\",\r\n\r\n\t\t\t\"types\": [\r\n\t\t\t\t{\r\n\t\t\t\t\t...\r\n\t\t\t\t}\r\n\t\t\t]\r\n\t\t}\r\n\t]\r\n}\r\n```\r\n - Support for enumerations\r\n```javascript\r\n{\r\n\t\"name\": \"Weekdays\",\r\n\t\"target\": \"Scala\",\r\n\t\"type\": \"enumeration\",\r\n\t\"doc\": \"The days of the week\",\r\n\r\n\t\"types\": [\r\n\t\t\"Sunday\",\r\n\t\t{\r\n\t\t\t\"doc\": \"A day that is documented\",\r\n\t\t\t\"name: \"Monday\"\r\n\t\t},\r\n\t\t\"Tuesday\",\r\n\t\t...,\r\n\t\t\"Saturday\"\r\n\t]\r\n}\r\n```\r\n - Support for lazy parameters\r\n```javascript\r\n{\r\n\t\"name\": \"LogElement\",\r\n\t\"target\": \"Scala\",\r\n\t\"type\": \"record\",\r\n\r\n\t\"fields\": [\r\n\t\t{\r\n\t\t\t\"name\": \"message\",\r\n\t\t\t\"type\": \"lazy string\"\r\n\t\t}\r\n\t]\r\n}\r\n```\r\n - Support for repeated parameters (mapped to Java or Scala `Array`s)\r\n```javascript\r\n{\r\n\t\"name\": \"Parameterized\",\r\n\t\"target\": \"Scala\",\r\n\t\"type\": \"record\",\r\n\r\n\t\"fields\": [\r\n\t\t{\r\n\t\t\t\"name\": \"parameters\",\r\n\t\t\t\"type\": \"Type*\"\r\n\t\t}\r\n\t]\r\n}\r\n```\r\n\r\n### About the `since` member\r\n\r\nThe `since` member can appear only in the definition of a `field`. It indicates that a field `f` exists in a `protocol` or `record` since the version specified. If a field definition has a `since` member, then it must provides the `default` member, which will tell what is the default value for this `field`.\r\n\r\nA field without a `since` member is assumed to exist since the first version of the schema.\r\n\r\n### About the `default` member\r\n\r\nThe `default` member can appear only in the definition of a `field`. It indicates the default value for a field (i.e. the value that this field will have when a record is constructed using a deprecated constructor that does not allow setting this field explicitly.) This member can contain simple expressions that **must compile and evaluate to the same value in Java and in Scala**. It is required for fields that have a `since` member.\r\n\r\n```javascript\r\n{\r\n\t\"types\": [\r\n\t\t{\r\n\t\t\t\"name\": \"ParameterizedType\",\r\n\t\t\t\"target\": \"Scala\",\r\n\t\t\t\"type\": \"record\",\r\n\r\n\t\t\t\"fields\": [\r\n\t\t\t\t{\r\n\t\t\t\t\t\"name\": \"typeName\",\r\n\t\t\t\t\t\"type\": \"string\"\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\t\"name\": \"parameter\",\r\n\t\t\t\t\t\"type\": \"Type\",\r\n\t\t\t\t\t\"since\": \"0.2.0\",\r\n\t\t\t\t\t\"default\": \"new Type(\\\"hello\\\")\"\r\n\t\t\t\t}\r\n\t\t\t]\r\n\t\t},\r\n\t\t{\r\n\t\t\t\"name\": \"Type\",\r\n\t\t\t\"type\": \"record\",\r\n\t\t\t\"target\": \"Scala\",\r\n\t\t\t\"fields\": [\r\n\t\t\t\t\"name\": \"typeName\",\r\n\t\t\t\t\"type\": \"string\"\r\n\t\t\t]\r\n\t\t}\r\n\t]\r\n}\r\n```\r\n\r\n### Implementation of the definitions\r\n\r\nHow does the following schema map to Scala and Java? (`target` has been omitted)\r\n\r\n```javascript\r\n{\r\n\t\"namespace\": \"com.example\",\r\n\r\n\t\"types\": [\r\n\t\t{\r\n\t\t\t\"name\": \"Greetings\",\r\n\t\t\t\"doc\": \"A greeting protocol\",\r\n\t\t\t\"type\": \"protocol\",\r\n\r\n\t\t\t\"fields\": [\r\n\t\t\t\t{\r\n\t\t\t\t\t\"name\": \"message\",\r\n\t\t\t\t\t\"doc\": \"The message of the Greeting\"\r\n\t\t\t\t\t\"type\": \"string\",\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\t\"name\": \"header\",\r\n\t\t\t\t\t\"doc\": \"The header of the Greeting\"\r\n\t\t\t\t\t\"type\": \"GreetingHeader\",\r\n\t\t\t\t\t\"since\": \"0.2.0\"\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\t\"name\": \"lazyField\",\r\n\t\t\t\t\t\"doc\": \"I'm only here to show what lazy parameters look like\",\r\n\t\t\t\t\t\"type\": \"lazy string\",\r\n\t\t\t\t\t\"since\": \"0.1.0\"\r\n\t\t\t\t}\r\n\t\t\t],\r\n\r\n\t\t\t\"types\": [\r\n\t\t\t\t{\r\n\t\t\t\t\t\"name\": \"SimpleGreeting\",\r\n\t\t\t\t\t\"type\": \"record\",\r\n\t\t\t\t\t\"doc\": \"A Greeting in its simplest form\"\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\t\"name\": \"GreetingWithAttachments\",\r\n\t\t\t\t\t\"type\": \"record\",\r\n\t\t\t\t\t\"doc\": \"A Greeting with attachments\",\r\n\r\n\t\t\t\t\t\"fields\": [\r\n\t\t\t\t\t\t{\r\n\t\t\t\t\t\t\t\"name\": \"attachments\",\r\n\t\t\t\t\t\t\t\"type\": \"java.io.File*\",\r\n\t\t\t\t\t\t\t\"doc\": \"The files attached to the greeting\"\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t]\r\n\t\t\t\t}\r\n\t\t\t]\r\n\t\t},\r\n\t\t{\r\n\t\t\t\"name\": \"GreetingHeader\",\r\n\t\t\t\"type\": \"record\",\r\n\t\t\t\"doc\": \"Meta information of a Greeting\",\r\n\r\n\t\t\t\"fields\": [\r\n\t\t\t\t{\r\n\t\t\t\t\t\"name\": \"created\",\r\n\t\t\t\t\t\"doc\": \"Creation date\",\r\n\t\t\t\t\t\"type\": \"java.util.Date\"\r\n\t\t\t\t\t\"default\": \"new java.util.Date()\",\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\t\"name\": \"priority\",\r\n\t\t\t\t\t\"doc\": \"The priority of this Greeting\",\r\n\t\t\t\t\t\"type\": \"PriorityLevel\",\r\n\t\t\t\t\t\"since\": \"0.3.0\"\r\n\t\t\t\t\t\"default\": \"PriorityLevel.Medium\"\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\t\"name\": \"author\",\r\n\t\t\t\t\t\"doc\": \"The author of the Greeting\"\r\n\t\t\t\t\t\"type\": \"string\",\r\n\t\t\t\t\t\"default\": \"Unknown\"\r\n\t\t\t\t}\r\n\t\t\t]\r\n\t\t},\r\n\t\t{\r\n\t\t\t\"name\": \"PriorityLevel\",\r\n\t\t\t\"type\": \"enumeration\",\r\n\t\t\t\"doc\": \"Priority levels\",\r\n\r\n\t\t\t\"types\": [\r\n\t\t\t\t\"Low\",\r\n\t\t\t\t{\r\n\t\t\t\t\t\"name\": \"Medium\",\r\n\t\t\t\t\t\"doc\": \"Default priority level\",\r\n\t\t\t\t},\r\n\t\t\t\t\"High\"\r\n\t\t\t]\r\n\t\t}\r\n\t]\r\n}\r\n```\r\n\r\n#### In Scala\r\n\r\n```scala\r\npackage com.example\r\n/** A greeting protocol */\r\nsealed abstract class Greetings(\r\n  /** The message of the Greeting */\r\n  val message: String,\r\n  /** The header of the Greeting */\r\n  val header: GreetingHeader,\r\n  _lazyField: => String)  {\r\n  def this(message: String) = this(message, new GreetingHeader(new java.util.Date(), \"Unknown\"), expensiveComputation())\r\n  def this(message: String, lazyField: => String) = this(message, new GreetingHeader(new java.util.Date(), \"Unknown\"), lazyField)\r\n  \r\n  /** I'm only here to show what lazy parameters look like */\r\n  lazy val lazyField: String = _lazyField\r\n  override def equals(o: Any): Boolean = o match {\r\n    case x: Greetings => super.equals(o) // We have lazy members, so use object identity to avoid circularity.\r\n    case _ => false\r\n  }\r\n  override def hashCode: Int = {\r\n    super.hashCode\r\n  }\r\n  override def toString: String = {\r\n    \"Greetings(\" + message + \", \" + header + \", \" + lazyField + \")\"\r\n  }\r\n}\r\n\r\n/** A Greeting in its simplest form */\r\nfinal class SimpleGreeting(\r\n  message: String,\r\n  header: GreetingHeader,\r\n  lazyField: => String) extends Greetings(message, header, lazyField) {\r\n  def this(message: String) = this(message, new GreetingHeader(new java.util.Date(), \"Unknown\"), expensiveComputation())\r\n  def this(message: String, lazyField: => String) = this(message, new GreetingHeader(new java.util.Date(), \"Unknown\"), lazyField)\r\n  \r\n  \r\n  override def equals(o: Any): Boolean = o match {\r\n    case x: SimpleGreeting => super.equals(o) // We have lazy members, so use object identity to avoid circularity.\r\n    case _ => false\r\n  }\r\n  override def hashCode: Int = {\r\n    super.hashCode\r\n  }\r\n  override def toString: String = {\r\n    \"SimpleGreeting(\" + message + \", \" + header + \", \" + lazyField + \")\"\r\n  }\r\n}\r\n\r\nobject SimpleGreeting {\r\n  def apply(message: String): SimpleGreeting = new SimpleGreeting(message, new GreetingHeader(new java.util.Date(), \"Unknown\"), expensiveComputation())\r\n  def apply(message: String, lazyField: => String): SimpleGreeting = new SimpleGreeting(message, new GreetingHeader(new java.util.Date(), \"Unknown\"), lazyField)\r\n  def apply(message: String, header: GreetingHeader, lazyField: => String): SimpleGreeting = new SimpleGreeting(message, header, lazyField)\r\n}\r\n\r\n/** A Greeting with attachments */\r\nfinal class GreetingWithAttachments(\r\n  message: String,\r\n  header: GreetingHeader,\r\n  lazyField: => String,\r\n  /** The files attached to the greeting */\r\n  val attachments: Array[java.io.File]) extends Greetings(message, header, lazyField) {\r\n  def this(message: String, attachments: Array[java.io.File]) = this(message, new GreetingHeader(new java.util.Date(), \"Unknown\"), expensiveComputation(), attachments)\r\n  def this(message: String, lazyField: => String, attachments: Array[java.io.File]) = this(message, new GreetingHeader(new java.util.Date(), \"Unknown\"), lazyField, attachments)\r\n  \r\n  \r\n  override def equals(o: Any): Boolean = o match {\r\n    case x: GreetingWithAttachments => super.equals(o) // We have lazy members, so use object identity to avoid circularity.\r\n    case _ => false\r\n  }\r\n  override def hashCode: Int = {\r\n    super.hashCode\r\n  }\r\n  override def toString: String = {\r\n    \"GreetingWithAttachments(\" + message + \", \" + header + \", \" + lazyField + \", \" + attachments + \")\"\r\n  }\r\n}\r\n\r\nobject GreetingWithAttachments {\r\n  def apply(message: String, attachments: Array[java.io.File]): GreetingWithAttachments = new GreetingWithAttachments(message, new GreetingHeader(new java.util.Date(), \"Unknown\"), expensiveComputation(), attachments)\r\n  def apply(message: String, lazyField: => String, attachments: Array[java.io.File]): GreetingWithAttachments = new GreetingWithAttachments(message, new GreetingHeader(new java.util.Date(), \"Unknown\"), lazyField, attachments)\r\n  def apply(message: String, header: GreetingHeader, lazyField: => String, attachments: Array[java.io.File]): GreetingWithAttachments = new GreetingWithAttachments(message, header, lazyField, attachments)\r\n}\r\n\r\n/** Meta information of a Greeting */\r\nfinal class GreetingHeader(\r\n  /** Creation date */\r\n  val created: java.util.Date,\r\n  /** The priority of this Greeting */\r\n  val priority: PriorityLevel,\r\n  /** The author of the Greeting */\r\n  val author: String)  {\r\n  def this(created: java.util.Date, author: String) = this(created, PriorityLevel.Medium, author)\r\n  \r\n  \r\n  override def equals(o: Any): Boolean = o match {\r\n    case x: GreetingHeader => (this.created == x.created) && (this.priority == x.priority) && (this.author == x.author)\r\n    case _ => false\r\n  }\r\n  override def hashCode: Int = {\r\n    37 * (37 * (37 * (17 + created.##) + priority.##) + author.##)\r\n  }\r\n  override def toString: String = {\r\n    \"GreetingHeader(\" + created + \", \" + priority + \", \" + author + \")\"\r\n  }\r\n}\r\n\r\nobject GreetingHeader {\r\n  def apply(created: java.util.Date, author: String): GreetingHeader = new GreetingHeader(created, PriorityLevel.Medium, author)\r\n  def apply(created: java.util.Date, priority: PriorityLevel, author: String): GreetingHeader = new GreetingHeader(created, priority, author)\r\n}\r\n\r\n/** Priority levels */\r\nsealed abstract class PriorityLevel\r\nobject PriorityLevel {\r\n  \r\n  case object Low extends PriorityLevel\r\n  /** Default priority level */\r\n  case object Medium extends PriorityLevel\r\n  \r\n  case object High extends PriorityLevel\r\n}\r\n```\r\n\r\n#### In java\r\n\r\n```java\r\n==> com/example/GreetingHeader.java <==\r\npackage com.example;\r\n/** Meta information of a Greeting */\r\npublic final class GreetingHeader  {\r\n    /** Creation date */\r\n    private java.util.Date created;\r\n    /** The priority of this Greeting */\r\n    private PriorityLevel priority;\r\n    /** The author of the Greeting */\r\n    private String author;\r\n    public GreetingHeader(java.util.Date _created, String _author) {\r\n        super();\r\n        created = _created;\r\n        priority = PriorityLevel.Medium;\r\n        author = _author;\r\n    }\r\n    \r\n    public GreetingHeader(java.util.Date _created, PriorityLevel _priority, String _author) {\r\n        super();\r\n        created = _created;\r\n        priority = _priority;\r\n        author = _author;\r\n    }\r\n    public java.util.Date created() {\r\n        return this.created;\r\n    }\r\n    public PriorityLevel priority() {\r\n        return this.priority;\r\n    }\r\n    public String author() {\r\n        return this.author;\r\n    }\r\n    public boolean equals(Object obj) {\r\n        if (this == obj) {\r\n            return true;\r\n        } else if (!(obj instanceof GreetingHeader)) {\r\n            return false;\r\n        } else {\r\n            GreetingHeader o = (GreetingHeader)obj;\r\n            return created().equals(o.created()) && priority().equals(o.priority()) && author().equals(o.author());\r\n        }\r\n    }\r\n    public int hashCode() {\r\n        return 37 * (37 * (37 * (17 + created().hashCode()) + priority().hashCode()) + author().hashCode());\r\n    }\r\n    public String toString() {\r\n        return  \"GreetingHeader(\"  + \"created: \" + created() + \", \" + \"priority: \" + priority() + \", \" + \"author: \" + author() + \")\";\r\n    }\r\n}\r\n\r\n\r\n==> com/example/GreetingWithAttachments.java <==\r\npackage com.example;\r\n/** A Greeting with attachments */\r\npublic final class GreetingWithAttachments extends Greetings {\r\n    /** The files attached to the greeting */\r\n    private java.io.File[] attachments;\r\n    public GreetingWithAttachments(String _message, java.io.File[] _attachments) {\r\n        super(_message, new GreetingHeader(new java.util.Date(), \"Unknown\"), expensiveComputation());\r\n        attachments = _attachments;\r\n    }\r\n    \r\n    public GreetingWithAttachments(String _message, Lazy<String> _lazyField, java.io.File[] _attachments) {\r\n        super(_message, new GreetingHeader(new java.util.Date(), \"Unknown\"), _lazyField);\r\n        attachments = _attachments;\r\n    }\r\n    \r\n    public GreetingWithAttachments(String _message, GreetingHeader _header, Lazy<String> _lazyField, java.io.File[] _attachments) {\r\n        super(_message, _header, _lazyField);\r\n        attachments = _attachments;\r\n    }\r\n    public java.io.File[] attachments() {\r\n        return this.attachments;\r\n    }\r\n    public boolean equals(Object obj) {\r\n        return this == obj; // We have lazy members, so use object identity to avoid circularity.\r\n    }\r\n    public int hashCode() {\r\n        return super.hashCode();\r\n    }\r\n    public String toString() {\r\n        return  \"GreetingWithAttachments(\"  + \"message: \" + message() + \", \" + \"header: \" + header() + \", \" + \"lazyField: \" + lazyField() + \", \" + \"attachments: \" + attachments() + \")\";\r\n    }\r\n}\r\n\r\n\r\n==> com/example/Greetings.java <==\r\npackage com.example;\r\n/** A greeting protocol */\r\npublic abstract class Greetings  {\r\n    /** The message of the Greeting */\r\n    private String message;\r\n    /** The header of the Greeting */\r\n    private GreetingHeader header;\r\n    /** I'm only here to show what lazy parameters look like */\r\n    private Lazy<String> lazyField;\r\n    public Greetings(String _message) {\r\n        super();\r\n        message = _message;\r\n        header = new GreetingHeader(new java.util.Date(), \"Unknown\");\r\n        lazyField = expensiveComputation();\r\n    }\r\n    \r\n    public Greetings(String _message, Lazy<String> _lazyField) {\r\n        super();\r\n        message = _message;\r\n        header = new GreetingHeader(new java.util.Date(), \"Unknown\");\r\n        lazyField = _lazyField;\r\n    }\r\n    \r\n    public Greetings(String _message, GreetingHeader _header, Lazy<String> _lazyField) {\r\n        super();\r\n        message = _message;\r\n        header = _header;\r\n        lazyField = _lazyField;\r\n    }\r\n    public String message() {\r\n        return this.message;\r\n    }\r\n    public GreetingHeader header() {\r\n        return this.header;\r\n    }\r\n    public String lazyField() {\r\n        return this.lazyField.get();\r\n    }\r\n    public boolean equals(Object obj) {\r\n        return this == obj; // We have lazy members, so use object identity to avoid circularity.\r\n    }\r\n    public int hashCode() {\r\n        return super.hashCode();\r\n    }\r\n    public String toString() {\r\n        return  \"Greetings(\"  + \"message: \" + message() + \", \" + \"header: \" + header() + \", \" + \"lazyField: \" + lazyField() + \")\";\r\n    }\r\n}\r\n\r\n\r\n==> com/example/PriorityLevel.java <==\r\npackage com.example;\r\n/** Priority levels */\r\npublic enum PriorityLevel {\r\n    \r\n    Low,\r\n    /** Default priority level */\r\n    Medium,\r\n    \r\n    High\r\n}\r\n\r\n\r\n==> com/example/SimpleGreeting.java <==\r\npackage com.example;\r\n/** A Greeting in its simplest form */\r\npublic final class SimpleGreeting extends Greetings {\r\n    \r\n    public SimpleGreeting(String _message) {\r\n        super(_message, new GreetingHeader(new java.util.Date(), \"Unknown\"), expensiveComputation());\r\n        \r\n    }\r\n    \r\n    public SimpleGreeting(String _message, Lazy<String> _lazyField) {\r\n        super(_message, new GreetingHeader(new java.util.Date(), \"Unknown\"), _lazyField);\r\n        \r\n    }\r\n    \r\n    public SimpleGreeting(String _message, GreetingHeader _header, Lazy<String> _lazyField) {\r\n        super(_message, _header, _lazyField);\r\n        \r\n    }\r\n    \r\n    public boolean equals(Object obj) {\r\n        return this == obj; // We have lazy members, so use object identity to avoid circularity.\r\n    }\r\n    public int hashCode() {\r\n        return super.hashCode();\r\n    }\r\n    public String toString() {\r\n        return  \"SimpleGreeting(\"  + \"message: \" + message() + \", \" + \"header: \" + header() + \", \" + \"lazyField: \" + lazyField() + \")\";\r\n    }\r\n}\r\n```","created_at":"2015-07-24T13:19:46Z","updated_at":"2015-07-29T05:18:42Z","closed_at":null,"merged_at":null,"merge_commit_sha":"ba01e08f94f76058c92f28a3b11443c0ffd2352f","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/sbt/sbt-datatype/pulls/2/commits","review_comments_url":"https://api.github.com/repos/sbt/sbt-datatype/pulls/2/comments","review_comment_url":"https://api.github.com/repos/sbt/sbt-datatype/pulls/comments{/number}","comments_url":"https://api.github.com/repos/sbt/sbt-datatype/issues/2/comments","statuses_url":"https://api.github.com/repos/sbt/sbt-datatype/statuses/88d98979f6a3a4d1ec4cae7537af4dfb4f0c55df","head":{"label":"Duhemm:new-schema","ref":"new-schema","sha":"88d98979f6a3a4d1ec4cae7537af4dfb4f0c55df","user":{"login":"Duhemm","id":1765926,"avatar_url":"https://avatars.githubusercontent.com/u/1765926?v=3","gravatar_id":"","url":"https://api.github.com/users/Duhemm","html_url":"https://github.com/Duhemm","followers_url":"https://api.github.com/users/Duhemm/followers","following_url":"https://api.github.com/users/Duhemm/following{/other_user}","gists_url":"https://api.github.com/users/Duhemm/gists{/gist_id}","starred_url":"https://api.github.com/users/Duhemm/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Duhemm/subscriptions","organizations_url":"https://api.github.com/users/Duhemm/orgs","repos_url":"https://api.github.com/users/Duhemm/repos","events_url":"https://api.github.com/users/Duhemm/events{/privacy}","received_events_url":"https://api.github.com/users/Duhemm/received_events","type":"User","site_admin":false},"repo":{"id":39375853,"name":"sbt-datatype","full_name":"Duhemm/sbt-datatype","owner":{"login":"Duhemm","id":1765926,"avatar_url":"https://avatars.githubusercontent.com/u/1765926?v=3","gravatar_id":"","url":"https://api.github.com/users/Duhemm","html_url":"https://github.com/Duhemm","followers_url":"https://api.github.com/users/Duhemm/followers","following_url":"https://api.github.com/users/Duhemm/following{/other_user}","gists_url":"https://api.github.com/users/Duhemm/gists{/gist_id}","starred_url":"https://api.github.com/users/Duhemm/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Duhemm/subscriptions","organizations_url":"https://api.github.com/users/Duhemm/orgs","repos_url":"https://api.github.com/users/Duhemm/repos","events_url":"https://api.github.com/users/Duhemm/events{/privacy}","received_events_url":"https://api.github.com/users/Duhemm/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/Duhemm/sbt-datatype","description":"","fork":true,"url":"https://api.github.com/repos/Duhemm/sbt-datatype","forks_url":"https://api.github.com/repos/Duhemm/sbt-datatype/forks","keys_url":"https://api.github.com/repos/Duhemm/sbt-datatype/keys{/key_id}","collaborators_url":"https://api.github.com/repos/Duhemm/sbt-datatype/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/Duhemm/sbt-datatype/teams","hooks_url":"https://api.github.com/repos/Duhemm/sbt-datatype/hooks","issue_events_url":"https://api.github.com/repos/Duhemm/sbt-datatype/issues/events{/number}","events_url":"https://api.github.com/repos/Duhemm/sbt-datatype/events","assignees_url":"https://api.github.com/repos/Duhemm/sbt-datatype/assignees{/user}","branches_url":"https://api.github.com/repos/Duhemm/sbt-datatype/branches{/branch}","tags_url":"https://api.github.com/repos/Duhemm/sbt-datatype/tags","blobs_url":"https://api.github.com/repos/Duhemm/sbt-datatype/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/Duhemm/sbt-datatype/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/Duhemm/sbt-datatype/git/refs{/sha}","trees_url":"https://api.github.com/repos/Duhemm/sbt-datatype/git/trees{/sha}","statuses_url":"https://api.github.com/repos/Duhemm/sbt-datatype/statuses/{sha}","languages_url":"https://api.github.com/repos/Duhemm/sbt-datatype/languages","stargazers_url":"https://api.github.com/repos/Duhemm/sbt-datatype/stargazers","contributors_url":"https://api.github.com/repos/Duhemm/sbt-datatype/contributors","subscribers_url":"https://api.github.com/repos/Duhemm/sbt-datatype/subscribers","subscription_url":"https://api.github.com/repos/Duhemm/sbt-datatype/subscription","commits_url":"https://api.github.com/repos/Duhemm/sbt-datatype/commits{/sha}","git_commits_url":"https://api.github.com/repos/Duhemm/sbt-datatype/git/commits{/sha}","comments_url":"https://api.github.com/repos/Duhemm/sbt-datatype/comments{/number}","issue_comment_url":"https://api.github.com/repos/Duhemm/sbt-datatype/issues/comments{/number}","contents_url":"https://api.github.com/repos/Duhemm/sbt-datatype/contents/{+path}","compare_url":"https://api.github.com/repos/Duhemm/sbt-datatype/compare/{base}...{head}","merges_url":"https://api.github.com/repos/Duhemm/sbt-datatype/merges","archive_url":"https://api.github.com/repos/Duhemm/sbt-datatype/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/Duhemm/sbt-datatype/downloads","issues_url":"https://api.github.com/repos/Duhemm/sbt-datatype/issues{/number}","pulls_url":"https://api.github.com/repos/Duhemm/sbt-datatype/pulls{/number}","milestones_url":"https://api.github.com/repos/Duhemm/sbt-datatype/milestones{/number}","notifications_url":"https://api.github.com/repos/Duhemm/sbt-datatype/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/Duhemm/sbt-datatype/labels{/name}","releases_url":"https://api.github.com/repos/Duhemm/sbt-datatype/releases{/id}","created_at":"2015-07-20T09:46:24Z","updated_at":"2015-07-20T09:46:24Z","pushed_at":"2015-07-28T14:39:57Z","git_url":"git://github.com/Duhemm/sbt-datatype.git","ssh_url":"git@github.com:Duhemm/sbt-datatype.git","clone_url":"https://github.com/Duhemm/sbt-datatype.git","svn_url":"https://github.com/Duhemm/sbt-datatype","homepage":null,"size":177,"stargazers_count":0,"watchers_count":0,"language":"Scala","has_issues":false,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"sbt:master","ref":"master","sha":"6b06bbe45bfc4727fbee7ea3231c80c3227652b9","user":{"login":"sbt","id":1158012,"avatar_url":"https://avatars.githubusercontent.com/u/1158012?v=3","gravatar_id":"","url":"https://api.github.com/users/sbt","html_url":"https://github.com/sbt","followers_url":"https://api.github.com/users/sbt/followers","following_url":"https://api.github.com/users/sbt/following{/other_user}","gists_url":"https://api.github.com/users/sbt/gists{/gist_id}","starred_url":"https://api.github.com/users/sbt/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/sbt/subscriptions","organizations_url":"https://api.github.com/users/sbt/orgs","repos_url":"https://api.github.com/users/sbt/repos","events_url":"https://api.github.com/users/sbt/events{/privacy}","received_events_url":"https://api.github.com/users/sbt/received_events","type":"Organization","site_admin":false},"repo":{"id":36924597,"name":"sbt-datatype","full_name":"sbt/sbt-datatype","owner":{"login":"sbt","id":1158012,"avatar_url":"https://avatars.githubusercontent.com/u/1158012?v=3","gravatar_id":"","url":"https://api.github.com/users/sbt","html_url":"https://github.com/sbt","followers_url":"https://api.github.com/users/sbt/followers","following_url":"https://api.github.com/users/sbt/following{/other_user}","gists_url":"https://api.github.com/users/sbt/gists{/gist_id}","starred_url":"https://api.github.com/users/sbt/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/sbt/subscriptions","organizations_url":"https://api.github.com/users/sbt/orgs","repos_url":"https://api.github.com/users/sbt/repos","events_url":"https://api.github.com/users/sbt/events{/privacy}","received_events_url":"https://api.github.com/users/sbt/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/sbt/sbt-datatype","description":"","fork":false,"url":"https://api.github.com/repos/sbt/sbt-datatype","forks_url":"https://api.github.com/repos/sbt/sbt-datatype/forks","keys_url":"https://api.github.com/repos/sbt/sbt-datatype/keys{/key_id}","collaborators_url":"https://api.github.com/repos/sbt/sbt-datatype/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/sbt/sbt-datatype/teams","hooks_url":"https://api.github.com/repos/sbt/sbt-datatype/hooks","issue_events_url":"https://api.github.com/repos/sbt/sbt-datatype/issues/events{/number}","events_url":"https://api.github.com/repos/sbt/sbt-datatype/events","assignees_url":"https://api.github.com/repos/sbt/sbt-datatype/assignees{/user}","branches_url":"https://api.github.com/repos/sbt/sbt-datatype/branches{/branch}","tags_url":"https://api.github.com/repos/sbt/sbt-datatype/tags","blobs_url":"https://api.github.com/repos/sbt/sbt-datatype/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/sbt/sbt-datatype/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/sbt/sbt-datatype/git/refs{/sha}","trees_url":"https://api.github.com/repos/sbt/sbt-datatype/git/trees{/sha}","statuses_url":"https://api.github.com/repos/sbt/sbt-datatype/statuses/{sha}","languages_url":"https://api.github.com/repos/sbt/sbt-datatype/languages","stargazers_url":"https://api.github.com/repos/sbt/sbt-datatype/stargazers","contributors_url":"https://api.github.com/repos/sbt/sbt-datatype/contributors","subscribers_url":"https://api.github.com/repos/sbt/sbt-datatype/subscribers","subscription_url":"https://api.github.com/repos/sbt/sbt-datatype/subscription","commits_url":"https://api.github.com/repos/sbt/sbt-datatype/commits{/sha}","git_commits_url":"https://api.github.com/repos/sbt/sbt-datatype/git/commits{/sha}","comments_url":"https://api.github.com/repos/sbt/sbt-datatype/comments{/number}","issue_comment_url":"https://api.github.com/repos/sbt/sbt-datatype/issues/comments{/number}","contents_url":"https://api.github.com/repos/sbt/sbt-datatype/contents/{+path}","compare_url":"https://api.github.com/repos/sbt/sbt-datatype/compare/{base}...{head}","merges_url":"https://api.github.com/repos/sbt/sbt-datatype/merges","archive_url":"https://api.github.com/repos/sbt/sbt-datatype/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/sbt/sbt-datatype/downloads","issues_url":"https://api.github.com/repos/sbt/sbt-datatype/issues{/number}","pulls_url":"https://api.github.com/repos/sbt/sbt-datatype/pulls{/number}","milestones_url":"https://api.github.com/repos/sbt/sbt-datatype/milestones{/number}","notifications_url":"https://api.github.com/repos/sbt/sbt-datatype/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/sbt/sbt-datatype/labels{/name}","releases_url":"https://api.github.com/repos/sbt/sbt-datatype/releases{/id}","created_at":"2015-06-05T09:36:59Z","updated_at":"2015-06-13T23:05:52Z","pushed_at":"2015-07-28T14:39:57Z","git_url":"git://github.com/sbt/sbt-datatype.git","ssh_url":"git@github.com:sbt/sbt-datatype.git","clone_url":"https://github.com/sbt/sbt-datatype.git","svn_url":"https://github.com/sbt/sbt-datatype","homepage":null,"size":205,"stargazers_count":0,"watchers_count":0,"language":"Scala","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":1,"mirror_url":null,"open_issues_count":1,"forks":1,"open_issues":1,"watchers":0,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/sbt/sbt-datatype/pulls/2"},"html":{"href":"https://github.com/sbt/sbt-datatype/pull/2"},"issue":{"href":"https://api.github.com/repos/sbt/sbt-datatype/issues/2"},"comments":{"href":"https://api.github.com/repos/sbt/sbt-datatype/issues/2/comments"},"review_comments":{"href":"https://api.github.com/repos/sbt/sbt-datatype/pulls/2/comments"},"review_comment":{"href":"https://api.github.com/repos/sbt/sbt-datatype/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/sbt/sbt-datatype/pulls/2/commits"},"statuses":{"href":"https://api.github.com/repos/sbt/sbt-datatype/statuses/88d98979f6a3a4d1ec4cae7537af4dfb4f0c55df"}}}}