private static Object readSynchronizedCollectionFrom(
      Input input,
      Schema<?> schema,
      Object owner,
      IdStrategy strategy,
      boolean graph,
      Object collection,
      boolean ss,
      boolean list)
      throws IOException {
    if (graph) {
      // update the actual reference.
      ((GraphInput) input).updateLast(collection, owner);
    }

    final Wrapper wrapper = new Wrapper();
    Object c = input.mergeObject(wrapper, strategy.POLYMORPHIC_COLLECTION_SCHEMA);
    if (!graph || !((GraphInput) input).isCurrentMessageReference()) c = wrapper.value;
    try {
      fSynchronizedCollection_c.set(collection, c);
      // mutex is the object itself.
      fSynchronizedCollection_mutex.set(collection, collection);

      if (ss) fSynchronizedSortedSet_ss.set(collection, c);

      if (list) fSynchronizedList_list.set(collection, c);
    } catch (Exception e) {
      throw new RuntimeException(e);
    }

    return collection;
  }
  private static Object readCheckedCollectionFrom(
      Input input,
      Schema<?> schema,
      Object owner,
      IdStrategy strategy,
      boolean graph,
      Object collection,
      boolean ss,
      boolean list)
      throws IOException {
    if (graph) {
      // update the actual reference.
      ((GraphInput) input).updateLast(collection, owner);
    }

    final Wrapper wrapper = new Wrapper();
    Object c = input.mergeObject(wrapper, strategy.POLYMORPHIC_COLLECTION_SCHEMA);
    if (!graph || !((GraphInput) input).isCurrentMessageReference()) c = wrapper.value;

    if (1 != input.readFieldNumber(schema)) throw new ProtostuffException("Corrupt input.");

    Object type = input.mergeObject(wrapper, strategy.CLASS_SCHEMA);
    if (!graph || !((GraphInput) input).isCurrentMessageReference()) type = wrapper.value;
    try {
      fCheckedCollection_c.set(collection, c);
      fCheckedCollection_type.set(collection, type);

      if (ss) fCheckedSortedSet_ss.set(collection, c);

      if (list) fCheckedList_list.set(collection, c);
    } catch (Exception e) {
      throw new RuntimeException(e);
    }

    return collection;
  }
  @SuppressWarnings("unchecked")
  static Object readObjectFrom(
      Input input, Schema<?> schema, Object owner, IdStrategy strategy, final int number)
      throws IOException {
    final boolean graph = input instanceof GraphInput;
    Object ret = null;
    switch (number) {
      case ID_EMPTY_SET:
        if (0 != input.readUInt32()) throw new ProtostuffException("Corrupt input.");

        if (graph) {
          // update the actual reference.
          ((GraphInput) input).updateLast(Collections.EMPTY_SET, owner);
        }

        ret = Collections.EMPTY_SET;
        break;

      case ID_EMPTY_LIST:
        if (0 != input.readUInt32()) throw new ProtostuffException("Corrupt input.");

        if (graph) {
          // update the actual reference.
          ((GraphInput) input).updateLast(Collections.EMPTY_LIST, owner);
        }

        ret = Collections.EMPTY_LIST;
        break;

      case ID_SINGLETON_SET:
        {
          if (0 != input.readUInt32()) throw new ProtostuffException("Corrupt input.");

          final Object collection = iSingletonSet.newInstance();
          if (graph) {
            // update the actual reference.
            ((GraphInput) input).updateLast(collection, owner);
          }

          final int next = input.readFieldNumber(schema);
          if (next == 0) {
            // null element
            return collection;
          }

          if (next != 1) throw new ProtostuffException("Corrupt input");

          final Wrapper wrapper = new Wrapper();
          Object element = input.mergeObject(wrapper, strategy.OBJECT_SCHEMA);
          if (!graph || !((GraphInput) input).isCurrentMessageReference()) element = wrapper.value;

          try {
            fSingletonSet_element.set(collection, element);
          } catch (Exception e) {
            throw new RuntimeException(e);
          }

          ret = collection;
          break;
        }

      case ID_SINGLETON_LIST:
        {
          if (0 != input.readUInt32()) throw new ProtostuffException("Corrupt input.");

          final Object collection = iSingletonList.newInstance();
          if (graph) {
            // update the actual reference.
            ((GraphInput) input).updateLast(collection, owner);
          }

          final int next = input.readFieldNumber(schema);
          if (next == 0) {
            // null element
            return collection;
          }

          if (next != 1) throw new ProtostuffException("Corrupt input.");

          final Wrapper wrapper = new Wrapper();
          Object element = input.mergeObject(wrapper, strategy.OBJECT_SCHEMA);
          if (!graph || !((GraphInput) input).isCurrentMessageReference()) element = wrapper.value;

          try {
            fSingletonList_element.set(collection, element);
          } catch (Exception e) {
            throw new RuntimeException(e);
          }

          ret = collection;
          break;
        }

      case ID_SET_FROM_MAP:
        {
          final Object collection = iSetFromMap.newInstance();
          if (graph) {
            // update the actual reference.
            ((GraphInput) input).updateLast(collection, owner);
          }

          final Wrapper wrapper = new Wrapper();
          Object m = input.mergeObject(wrapper, strategy.POLYMORPHIC_MAP_SCHEMA);
          if (!graph || !((GraphInput) input).isCurrentMessageReference()) m = wrapper.value;

          try {
            fSetFromMap_m.set(collection, m);
            fSetFromMap_s.set(collection, ((Map<?, ?>) m).keySet());
          } catch (Exception e) {
            throw new RuntimeException(e);
          }

          ret = collection;
          break;
        }

      case ID_COPIES_LIST:
        {
          if (0 != input.readUInt32()) throw new ProtostuffException("Corrupt input.");

          final Object collection = iCopiesList.newInstance();
          if (graph) {
            // update the actual reference.
            ((GraphInput) input).updateLast(collection, owner);
          }

          if (1 != input.readFieldNumber(schema)) throw new ProtostuffException("Corrupt input.");

          final int n = input.readUInt32(), next = input.readFieldNumber(schema);

          if (next == 0) {
            // null element
            try {
              fCopiesList_n.setInt(collection, n);
            } catch (Exception e) {
              throw new RuntimeException(e);
            }

            return collection;
          }

          if (next != 2) throw new ProtostuffException("Corrupt input.");

          final Wrapper wrapper = new Wrapper();
          Object element = input.mergeObject(wrapper, strategy.OBJECT_SCHEMA);
          if (!graph || !((GraphInput) input).isCurrentMessageReference()) element = wrapper.value;

          try {
            fCopiesList_n.setInt(collection, n);
            fCopiesList_element.set(collection, element);
          } catch (Exception e) {
            throw new RuntimeException(e);
          }

          ret = collection;
          break;
        }

      case ID_UNMODIFIABLE_COLLECTION:
        ret =
            readUnmodifiableCollectionFrom(
                input,
                schema,
                owner,
                strategy,
                graph,
                iUnmodifiableCollection.newInstance(),
                false,
                false);
        break;
      case ID_UNMODIFIABLE_SET:
        ret =
            readUnmodifiableCollectionFrom(
                input,
                schema,
                owner,
                strategy,
                graph,
                iUnmodifiableSet.newInstance(),
                false,
                false);
        break;
      case ID_UNMODIFIABLE_SORTED_SET:
        ret =
            readUnmodifiableCollectionFrom(
                input,
                schema,
                owner,
                strategy,
                graph,
                iUnmodifiableSortedSet.newInstance(),
                true,
                false);
        break;
      case ID_UNMODIFIABLE_LIST:
        ret =
            readUnmodifiableCollectionFrom(
                input,
                schema,
                owner,
                strategy,
                graph,
                iUnmodifiableList.newInstance(),
                false,
                true);
        break;
      case ID_UNMODIFIABLE_RANDOM_ACCESS_LIST:
        ret =
            readUnmodifiableCollectionFrom(
                input,
                schema,
                owner,
                strategy,
                graph,
                iUnmodifiableRandomAccessList.newInstance(),
                false,
                true);
        break;

      case ID_SYNCHRONIZED_COLLECTION:
        ret =
            readSynchronizedCollectionFrom(
                input,
                schema,
                owner,
                strategy,
                graph,
                iSynchronizedCollection.newInstance(),
                false,
                false);
        break;
      case ID_SYNCHRONIZED_SET:
        ret =
            readSynchronizedCollectionFrom(
                input,
                schema,
                owner,
                strategy,
                graph,
                iSynchronizedSet.newInstance(),
                false,
                false);
        break;
      case ID_SYNCHRONIZED_SORTED_SET:
        ret =
            readSynchronizedCollectionFrom(
                input,
                schema,
                owner,
                strategy,
                graph,
                iSynchronizedSortedSet.newInstance(),
                true,
                false);
        break;
      case ID_SYNCHRONIZED_LIST:
        ret =
            readSynchronizedCollectionFrom(
                input,
                schema,
                owner,
                strategy,
                graph,
                iSynchronizedList.newInstance(),
                false,
                true);
        break;
      case ID_SYNCHRONIZED_RANDOM_ACCESS_LIST:
        ret =
            readSynchronizedCollectionFrom(
                input,
                schema,
                owner,
                strategy,
                graph,
                iSynchronizedRandomAccessList.newInstance(),
                false,
                true);
        break;

      case ID_CHECKED_COLLECTION:
        ret =
            readCheckedCollectionFrom(
                input,
                schema,
                owner,
                strategy,
                graph,
                iCheckedCollection.newInstance(),
                false,
                false);
        break;
      case ID_CHECKED_SET:
        ret =
            readCheckedCollectionFrom(
                input, schema, owner, strategy, graph, iCheckedSet.newInstance(), false, false);
        break;
      case ID_CHECKED_SORTED_SET:
        ret =
            readCheckedCollectionFrom(
                input,
                schema,
                owner,
                strategy,
                graph,
                iCheckedSortedSet.newInstance(),
                true,
                false);
        break;
      case ID_CHECKED_LIST:
        ret =
            readCheckedCollectionFrom(
                input, schema, owner, strategy, graph, iCheckedList.newInstance(), false, true);
        break;
      case ID_CHECKED_RANDOM_ACCESS_LIST:
        ret =
            readCheckedCollectionFrom(
                input,
                schema,
                owner,
                strategy,
                graph,
                iCheckedRandomAccessList.newInstance(),
                false,
                true);
        break;

      case ID_ENUM_SET:
        {
          final Collection<?> es = strategy.resolveEnumFrom(input).newEnumSet();

          if (graph) {
            // update the actual reference.
            ((GraphInput) input).updateLast(es, owner);
          }

          // TODO enum schema
          strategy.COLLECTION_SCHEMA.mergeFrom(input, (Collection<Object>) es);
          return es;
        }

      case ID_COLLECTION:
        {
          final Collection<Object> collection = strategy.resolveCollectionFrom(input).newMessage();

          if (graph) {
            // update the actual reference.
            ((GraphInput) input).updateLast(collection, owner);
          }

          strategy.COLLECTION_SCHEMA.mergeFrom(input, collection);

          return collection;
        }

      default:
        throw new ProtostuffException("Corrupt input.");
    }

    if (0 != input.readFieldNumber(schema)) throw new ProtostuffException("Corrupt input.");

    return ret;
  }