override def apply()

in ratatool-diffy/src/main/scala/com/spotify/ratatool/diffy/ProtoBufDiffy.scala [35:128]


  override def apply(x: T, y: T): Seq[Delta] =
    diff(Option(x), Option(y), descriptor.getFields.asScala.toList, "")

  // Descriptor is not serializable
  private lazy val descriptor: Descriptor =
    implicitly[ClassTag[T]].runtimeClass
      .getMethod("getDescriptor")
      .invoke(null)
      .asInstanceOf[Descriptor]

  private def diff(
    x: Option[AbstractMessage],
    y: Option[AbstractMessage],
    fields: Seq[FieldDescriptor],
    root: String
  ): Seq[Delta] = {
    def getField(f: FieldDescriptor)(m: AbstractMessage): Option[AnyRef] =
      if (f.isRepeated) {
        Option(m.getField(f))
      } else {
        if (m.hasField(f)) Option(m.getField(f)) else None
      }

    def getFieldDescriptor(f: FieldDescriptor, s: String): FieldDescriptor = {
      f.getMessageType.getFields.asScala.find(field => field.getName == s) match {
        case Some(d) => d
        case None    => throw new Exception(s"Field $s not found in ${f.getFullName}")
      }
    }

    fields
      .flatMap { f =>
        val name = f.getName
        val fullName = if (root.isEmpty) name else root + "." + name
        if (f.isRepeated && unordered.contains(fullName)) {
          if (
            f.getJavaType == JavaType.MESSAGE
            && unorderedFieldKeys.contains(fullName)
          ) {
            val l = x
              .flatMap(outer =>
                Option(outer.getField(f).asInstanceOf[java.util.List[AbstractMessage]].asScala)
              )
              .getOrElse(List())
              .flatMap(inner =>
                Try(getFieldDescriptor(f, unorderedFieldKeys(fullName))).toOption
                  .flatMap(fd => getField(fd)(inner))
                  .map(k => (k, inner))
              )
              .toMap
            val r = y
              .flatMap(outer =>
                Option(outer.getField(f).asInstanceOf[java.util.List[AbstractMessage]].asScala)
              )
              .getOrElse(List())
              .flatMap(inner =>
                Try(getFieldDescriptor(f, unorderedFieldKeys(fullName))).toOption
                  .flatMap(fd => getField(fd)(inner))
                  .map(k => (k, inner))
              )
              .toMap
            (l.keySet ++ r.keySet).flatMap(k =>
              diff(l.get(k), r.get(k), f.getMessageType.getFields.asScala.toList, fullName)
            )
          } else {
            val a = x
              .flatMap(r => Option(r.getField(f).asInstanceOf[java.util.List[AbstractMessage]]))
              .map(sortList)
            val b = y
              .flatMap(r => Option(r.getField(f).asInstanceOf[java.util.List[AbstractMessage]]))
              .map(sortList)
            if (a == b) Nil else Seq(Delta(fullName, a, b, delta(a.orNull, b.orNull)))
          }
        } else {
          f.getJavaType match {
            case JavaType.MESSAGE if !f.isRepeated =>
              val a = x.flatMap(m => getField(f)(m).asInstanceOf[Option[AbstractMessage]])
              val b = y.flatMap(m => getField(f)(m).asInstanceOf[Option[AbstractMessage]])
              if (a.isEmpty && b.isEmpty) {
                Nil
              } else if (a.isEmpty || b.isEmpty) {
                Seq(Delta(fullName, a, b, UnknownDelta))
              } else {
                diff(a, b, f.getMessageType.getFields.asScala.toList, fullName)
              }
            case _ =>
              val a = x.flatMap(r => Option(r.getField(f)))
              val b = y.flatMap(r => Option(r.getField(f)))
              if (a == b) Nil else Seq(Delta(fullName, a, b, delta(a.orNull, b.orNull)))
          }
        }
      }
      .filter(d => !ignore.contains(d.field))
  }