Permalink
Browse files

[split] scrooge: add extra fields to generated companion object for r…

…eflection use

RB_ID=278333
  • Loading branch information...
1 parent 674b72b commit 09211333df44c9e8df0b7acf8823283a2cb46f3b Eric Conlon committed with CI Feb 14, 2014
@@ -20,6 +20,7 @@ final class ThriftStructMetaData[T <: ThriftStruct](val codec: ThriftStructCodec
}.
mkString
}
+
/**
* The Class object for the ThriftStructCodec subclass.
*/
@@ -83,3 +84,16 @@ final class ThriftStructField[T <: ThriftStruct](val tfield: TField, val method:
*/
def getValue[R](struct: T): R = method.invoke(struct).asInstanceOf[R]
}
+
+/**
+ * Field information to be embedded in a generated struct's companion class.
+ * Allows for reflection on field types.
+ */
+final class ThriftStructFieldInfo(
+ val tfield: TField,
+ val isOptional: Boolean,
+ val manifest: Manifest[_],
+ val keyManifest: scala.Option[Manifest[_]],
+ val valueManifest: scala.Option[Manifest[_]]
+)
+
@@ -1,7 +1,7 @@
package {{package}}
import com.twitter.scrooge.{
- TFieldBlob, ThriftService, ThriftStruct, ThriftStructCodec, ThriftStructCodec3, ThriftUtil}
+ TFieldBlob, ThriftService, ThriftStruct, ThriftStructCodec, ThriftStructCodec3, ThriftStructFieldInfo, ThriftUtil}
import java.nio.ByteBuffer
import java.util.Arrays
import org.apache.thrift.protocol._
@@ -2,7 +2,7 @@
package {{package}}
import com.twitter.scrooge.{
- TFieldBlob, ThriftException, ThriftStruct, ThriftStructCodec3, ThriftUtil}
+ TFieldBlob, ThriftException, ThriftStruct, ThriftStructCodec3, ThriftStructFieldInfo, ThriftUtil}
import org.apache.thrift.protocol._
import org.apache.thrift.transport.{TMemoryBuffer, TTransport}
import java.nio.ByteBuffer
@@ -28,6 +28,31 @@ object {{StructName}} extends ThriftStructCodec3[{{StructName}}] {
{{/fields}}
/**
+ * Field information in declaration order.
+ */
+ lazy val fieldInfos: scala.List[ThriftStructFieldInfo] = scala.List[ThriftStructFieldInfo](
+{{#fields}}
+ new ThriftStructFieldInfo(
+ {{fieldConst}},
+ {{optional}},
+ {{fieldConst}}Manifest,
+{{#fieldKeyType}}
+ Some(implicitly[Manifest[{{fieldKeyType}}]]),
+{{/fieldKeyType}}
+{{^fieldKeyType}}
+ None,
+{{/fieldKeyType}}
+{{#fieldValueType}}
+ Some(implicitly[Manifest[{{fieldValueType}}]])
+{{/fieldValueType}}
+{{^fieldValueType}}
+ None
+{{/fieldValueType}}
+ )
+{{/fields|,}}
+ )
+
+ /**
* Checks that all required fields are non-null.
*/
def validate(_item: {{StructName}}) {
@@ -132,6 +132,16 @@ trait StructTemplate {
"isPrimitive" -> v(isPrimitive(field.fieldType)),
"primitiveFieldType" -> genPrimitiveType(field.fieldType, mutable = false),
"fieldType" -> genType(field.fieldType, mutable = false),
+ "fieldKeyType" -> v(field.fieldType match {
+ case MapType(keyType, _, _) => Some(genType(keyType))
+ case _ => None
+ }),
+ "fieldValueType" -> v(field.fieldType match {
+ case MapType(_, valueType, _) => Some(genType(valueType))
+ case ListType(valueType, _) => Some(genType(valueType))
+ case SetType(valueType, _) => Some(genType(valueType))
+ case _ => None
+ }),
"isImported" -> v(field.fieldType match {
case n: NamedType => n.scopePrefix.isDefined
case _ => false
@@ -10,16 +10,18 @@ import thrift.test._
// generation and testing and anyway requires scrooge-runtime for
// tests.
class ThriftStructMetaDataSpec extends Spec {
+ val metaData = XtructColl.metaData
+ val fields = metaData.fields.sortBy(_.id)
+
"Provide useful metadata" in {
val s = XtructColl(Map(1 -> 2L), Seq("test"), Set(10.toByte), 123)
- val metaData = XtructColl.metaData
assert(metaData.codecClass == XtructColl.getClass) // mustEqual doesn't work here
metaData.structClassName must be("thrift.test.XtructColl")
metaData.structName must be("XtructColl")
metaData.structClass must be(classOf[XtructColl])
- val Seq(f1, f2, f3, f4) = metaData.fields.sortBy(_.id)
+ val Seq(f1, f2, f3, f4) = fields
f1.name must be("a_map")
f1.id must be(1)
@@ -45,4 +47,39 @@ class ThriftStructMetaDataSpec extends Spec {
f4.manifest must be(Some(implicitly[Manifest[Int]]))
f4.getValue[Int](s) must be(123)
}
+
+ "fieldInfos" in {
+ (XtructColl.fieldInfos zip fields).foreach { pairs =>
+ val (info, field) = pairs
+ info.tfield.name must be(field.name)
+ // All of the XtructColl fields are required
+ info.isOptional must be(false)
+
+ field.id match {
+ case 1 =>
+ info.manifest must be(implicitly[Manifest[Map[Int, Long]]])
+ info.keyManifest must be(Some(implicitly[Manifest[Int]]))
+ info.valueManifest must be(Some(implicitly[Manifest[Long]]))
+ case 2 =>
+ info.manifest must be(implicitly[Manifest[Seq[String]]])
+ info.keyManifest must be(None)
+ info.valueManifest must be(Some(implicitly[Manifest[String]]))
+ case 3 =>
+ info.manifest must be(implicitly[Manifest[Set[Byte]]])
+ info.keyManifest must be(None)
+ info.valueManifest must be(Some(implicitly[Manifest[Byte]]))
+ case 4 =>
+ info.manifest must be(implicitly[Manifest[Int]])
+ info.keyManifest must be(None)
+ info.valueManifest must be(None)
+ case _ =>
+ throw new Exception("Unexpected field")
+ }
+ }
+
+ // All of the OneOfEachOptional fields are optional:
+ OneOfEachOptional.fieldInfos.foreach { fieldInfo =>
+ fieldInfo.isOptional must be(true)
+ }
+ }
}

0 comments on commit 0921133

Please sign in to comment.