public static <T> boolean readList(
    JsonReaderAdapter<T> adapter, ReadBuffer buffer, Collection<T> out) {
    if (buffer.available() == 0) return false;
    JsonReader reader = new JsonReader(buffer);
    try {
      reader.beginArray();
      if (!reader.hasNext()) return false;
      while (reader.hasNext()) out.add(adapter.fromJson(reader));
      reader.endArray();
      return true;
    } catch (Exception e) {
      throw exceptionReading("List<" + adapter + ">", e);
    }
  }
This explicitly constructs instances of model classes via manual parsing for a number of
reasons.

<ul>
  <li>Eliminates the need to keep separate model classes for proto3 vs json
  <li>Avoids magic field initialization which, can miss constructor guards
  <li>Allows us to safely re-use the json form in toString methods
  <li>Encourages logic to be based on the json shape of objects
  <li>Ensures the order and naming of the fields in json is stable
</ul>

<p>There is the up-front cost of creating this, and maintenance of this to consider. However,
this should be easy to justify as these objects don't change much at all.
zipkin/src/main/java/zipkin2/internal/JsonCodec.java