Skip to content

Commit

Permalink
Making the order of constructors returned deterministic
Browse files Browse the repository at this point in the history
  • Loading branch information
mccartney committed May 27, 2020
1 parent acbc81e commit 70c7c5e
Show file tree
Hide file tree
Showing 2 changed files with 32 additions and 3 deletions.
7 changes: 6 additions & 1 deletion core/src/main/scala/org/json4s/reflect/Reflector.scala
Expand Up @@ -132,7 +132,12 @@ object Reflector {
case None => scala.Array[Method]()
}
val applyExecutables = applyMethods.map{ m => new Executable(m) }
constructorDescriptors ++ createConstructorDescriptors(applyExecutables)
val all = constructorDescriptors ++ createConstructorDescriptors(applyExecutables)

// https://github.com/json4s/json4s/issues/371 no actual requirements for the order are known, but
// deterministic ordering regardless of non-determinism by java.reflect is needed
all.toList.sortBy(c =>
(!c.isPrimary, c.constructor.constructor == null, -c.params.size, c.toString))
}

def createConstructorDescriptors(ccs: Iterable[Executable]): Seq[ConstructorDescriptor] = {
Expand Down
28 changes: 26 additions & 2 deletions tests/src/test/scala/org/json4s/reflect/ReflectorSpec.scala
Expand Up @@ -2,8 +2,7 @@ package org.json4s.reflect

import org.json4s.reflect
import org.specs2.mutable.Specification

import ReflectorSpec.{Person, Dog, Cat}
import ReflectorSpec.{Cat, Dog, Person}

object ReflectorSpec {
case class Person(firstName: String, lastName: String) {
Expand Down Expand Up @@ -46,6 +45,8 @@ class ReflectorSpec extends Specification {
// the only human-visible constructor is visible as two - the constructor and the apply method
descriptor.constructors.size must_== 2
descriptor.constructors.count(_.isPrimary) must_== 1
descriptor.constructors(0).isPrimary must_== true
descriptor.constructors(1).isPrimary must_== false
}

"denote the annotated constructor as primary even if multiple exist" in {
Expand All @@ -55,5 +56,28 @@ class ReflectorSpec extends Specification {
descriptor.constructors.size must_== 3
descriptor.constructors.count(_.isPrimary) must_== 1
}

"retrieve constructors of a class in a deterministic order" in {
val klass = Reflector.scalaTypeOf(classOf[Person])
val descriptor = Reflector.describe(klass).asInstanceOf[reflect.ClassDescriptor]

descriptor.constructors.size must_== 4
val first = descriptor.constructors(0)
val second = descriptor.constructors(1)
val third = descriptor.constructors(2)
val fourth = descriptor.constructors(3)

first.params.map(_.name) must_== Seq("firstName", "lastName")
first.constructor.method must_== null
first.constructor.constructor must_!= null

second.params.map(_.name) must_== Seq("age")

third.params.map(_.name) must_== Seq("firstName", "lastName")
third.constructor.method must_!= null
third.constructor.constructor must_== null

fourth.params.map(_.name) must_== Seq("email")
}
}
}

0 comments on commit 70c7c5e

Please sign in to comment.