Permalink
Browse files

Merge pull request #139 from noahlz/issues/137

Resolve Issue #137 When suppressDefaultArgs = true, ObjectId fields without default value cause runtime error
  • Loading branch information...
rktoomey committed Oct 28, 2014
2 parents ef79e4f + a202c1a commit 3612c7687fe628146eef49d56b620ca3ad68083c
@@ -404,10 +404,16 @@ abstract class ConcreteGrater[X <: CaseClass](clazz: Class[X])(implicit ctx: Con
}
}
+ private def defaultValueInitializerName(idx: Int) = s"""apply$$default$$${idx}"""
+ private def methodExists(name: String) = ca.companionClass.getMethods.exists(m => m.getName.equals(name))
+
def defaultArg(field: SField): DefaultArg = {
+
+ val companionObjFieldInitializer = defaultValueInitializerName(field.idx + 1)
+
// always invoke default methods typed to object id
- if (field.tf.isOid) {
- DefaultArg(clazz, field, Some(ca.companionClass.getMethod(s"apply$$default$$${field.idx + 1}").invoke(ca.companionObject)))
+ if (field.tf.isOid && methodExists(companionObjFieldInitializer)) {
+ DefaultArg(clazz, field, Some(ca.companionClass.getMethod(companionObjFieldInitializer).invoke(ca.companionObject)))
}
else if (betterDefaults.contains(field)) {
betterDefaults(field)
@@ -422,13 +428,19 @@ abstract class ConcreteGrater[X <: CaseClass](clazz: Class[X])(implicit ctx: Con
protected[salat] lazy val betterDefaults = {
val builder = Map.newBuilder[SField, DefaultArg]
for (field <- indexedFields.filterNot(_.name == "_id")) {
- val defaultMethod = try {
+
+ val companionObjFieldInitializer = defaultValueInitializerName(field.idx + 1)
+
+ val defaultMethod = if (methodExists(companionObjFieldInitializer)) {
// Some(null) is actually "desirable" here because it allows using null as a default value for an ignored field
- Some(ca.companionClass.getMethod("apply$default$%d".format(field.idx + 1)).invoke(ca.companionObject))
- }
- catch {
- case _: Throwable => None // indicates no default value was supplied
+ try {
+ Some(ca.companionClass.getMethod(companionObjFieldInitializer).invoke(ca.companionObject))
+ }
+ catch {
+ case ex: ReflectiveOperationException => None // Indicates no default value was supplied
+ }
}
+ else None
builder += field -> DefaultArg(clazz, field, defaultMethod)
}
@@ -10,7 +10,7 @@ import org.specs2.mutable.Specification
*/
class JsonDefaultValuesSpec extends Specification with Logging with JsonMatchers {
- "JSON support" should {
+ "JSON support with default arg suppression disabled (the default)" should {
"evaluate default constructor argument when corresponding JSON property is missing" in {
val deserializedObj1 = grater[Probe].fromJSON("{}")
@@ -20,6 +20,32 @@ class JsonDefaultValuesSpec extends Specification with Logging with JsonMatchers
deserializedObj1.id should not be deserializedObj2.id
}
}
+
+ "JSON support with default arg suppression enabled" should {
+ implicit val ctx = new Context {
+ val name = "suppressDefault"
+ override val suppressDefaultArgs = true
+ }
+ "serialize instances with multiple ObjectId fields that do not have default values" in {
+ val father = Probe()
+ val child = ChildProbe(id = new ObjectId, parent = father.id)
+ val result = grater[ChildProbe].toCompactJSON(child)
+ result must not(throwA[NoSuchMethodException]) and beAnInstanceOf[String]
+ }
+ "serialize instances with Optional ObjectId fields that do not have default values" in {
+ val child = ChildProbeParentOptional(id = new ObjectId, parent = None)
+ val result = grater[ChildProbeParentOptional].toCompactJSON(child)
+ result must not(throwA[NoSuchMethodException]) and beAnInstanceOf[String]
+ }
+ "serialize instances with lists of ObjectIds that do not have default values" in {
+ val child = ChildProbeManyParents(id = new ObjectId, parents = Nil)
+ val result = grater[ChildProbeManyParents].toCompactJSON(child)
+ result must not(throwA[NoSuchMethodException]) and beAnInstanceOf[String]
+ }
+ }
}
case class Probe(id: ObjectId = new ObjectId())
+case class ChildProbe(id: ObjectId, parent: ObjectId)
+case class ChildProbeParentOptional(id: ObjectId, parent: Option[ObjectId])
+case class ChildProbeManyParents(id: ObjectId, parents: List[ObjectId])

0 comments on commit 3612c76

Please sign in to comment.