docs: private static boolean parseElementInternal(
        XmlPullParser parser,
        ArrayList<Type> context,
        Object destination,
        Type valueType,
        XmlNamespaceDictionary namespaceDictionary,
        CustomizeParser customizeParser)
        throws IOException, XmlPullParserException {
      // TODO(yanivi): method is too long; needs to be broken down into smaller methods and comment
      // better
      GenericXml genericXml = destination instanceof GenericXml ? (GenericXml) destination : null;
      @SuppressWarnings("unchecked")
      Map<String, Object> destinationMap =
          genericXml == null && destination instanceof Map<?, ?> ? Map.class.cast(destination) : null;
  
      // if there is a class, we want to put the data into, create the class Info for this
      ClassInfo classInfo =
          destinationMap != null || destination == null ? null : ClassInfo.of(destination.getClass());
      if (parser.getEventType() == XmlPullParser.START_DOCUMENT) {
        parser.next();
      }
      parseNamespacesForElement(parser, namespaceDictionary);
      // generic XML
      if (genericXml != null) {
        genericXml.namespaceDictionary = namespaceDictionary;
        String name = parser.getName();
        String namespace = parser.getNamespace();
        String alias = namespaceDictionary.getNamespaceAliasForUriErrorOnUnknown(namespace);
        genericXml.name = alias.length() == 0 ? name : alias + ":" + name;
      }
      // attributes
      if (destination != null) {
        int attributeCount = parser.getAttributeCount();
        for (int i = 0; i < attributeCount; i++) {
          // TODO(yanivi): can have repeating attribute values, e.g. "@a=value1 @a=value2"?
          String attributeName = parser.getAttributeName(i);
          String attributeNamespace = parser.getAttributeNamespace(i);
          String attributeAlias =
              attributeNamespace.length() == 0
                  ? ""
                  : namespaceDictionary.getNamespaceAliasForUriErrorOnUnknown(attributeNamespace);
          String fieldName = getFieldName(true, attributeAlias, attributeNamespace, attributeName);
          Field field = classInfo == null ? null : classInfo.getField(fieldName);
          parseAttributeOrTextContent(
              parser.getAttributeValue(i),
              field,
              valueType,
              context,
              destination,
              genericXml,
              destinationMap,
              fieldName);
        }
      }
      Field field;
      ArrayValueMap arrayValueMap = new ArrayValueMap(destination);
      boolean isStopped = false;
      // TODO(yanivi): support Void type as "ignore" element/attribute
      main:
      while (true) {
        int event = parser.next();
        switch (event) {
          case XmlPullParser.END_DOCUMENT:
            isStopped = true;
            break main;
          case XmlPullParser.END_TAG:
            isStopped =
                customizeParser != null
                    && customizeParser.stopAfterEndTag(parser.getNamespace(), parser.getName());
            break main;
          case XmlPullParser.TEXT:
            // parse text content
            if (destination != null) {
              field = classInfo == null ? null : classInfo.getField(TEXT_CONTENT);
              parseAttributeOrTextContent(
                  parser.getText(),
                  field,
                  valueType,
                  context,
                  destination,
                  genericXml,
                  destinationMap,
                  TEXT_CONTENT);
            }
            break;
          case XmlPullParser.START_TAG:
            if (customizeParser != null
                && customizeParser.stopBeforeStartTag(parser.getNamespace(), parser.getName())) {
              isStopped = true;
              break main;
            }
            if (destination == null) {
              parseTextContentForElement(parser, context, true, null);
            } else {
              // element
              parseNamespacesForElement(parser, namespaceDictionary);
              String namespace = parser.getNamespace();
              String alias = namespaceDictionary.getNamespaceAliasForUriErrorOnUnknown(namespace);
  
              //  get the "real" field name of the
              String fieldName = getFieldName(false, alias, namespace, parser.getName());
  
              // fetch the field from the classInfo
              field = classInfo == null ? null : classInfo.getField(fieldName);
              Type fieldType = field == null ? valueType : field.getGenericType();
              fieldType = Data.resolveWildcardTypeOrTypeVariable(context, fieldType);
              // field type is now class, parameterized type, or generic array type
              // resolve a parameterized type to a class
              Class<?> fieldClass = fieldType instanceof Class<?> ? (Class<?>) fieldType : null;
              if (fieldType instanceof ParameterizedType) {
                fieldClass = Types.getRawClass((ParameterizedType) fieldType);
              }
              boolean isArray = Types.isArray(fieldType);
              // text content
              boolean ignore = field == null && destinationMap == null && genericXml == null;
              // is the field an Enum
              boolean isEnum = fieldClass != null && fieldClass.isEnum();
              if (ignore || Data.isPrimitive(fieldType) || isEnum) {
                int level = 1;
                while (level != 0) {
                  switch (parser.next()) {
                    case XmlPullParser.END_DOCUMENT:
                      isStopped = true;
                      break main;
                    case XmlPullParser.START_TAG:
                      level++;
                      break;
                    case XmlPullParser.END_TAG:
                      level--;
                      break;
                    case XmlPullParser.TEXT:
                      if (!ignore && level == 1) {
                        parseAttributeOrTextContent(
                            parser.getText(),
                            field,
                            valueType,
                            context,
                            destination,
                            genericXml,
                            destinationMap,
                            fieldName);
                      }
                      break;
                    default:
                      break;
                  }
                }
              } else if (fieldType == null
                  || fieldClass != null && Types.isAssignableToOrFrom(fieldClass, Map.class)) {
                // store the element as a map
                Map<String, Object> mapValue = Data.newMapInstance(fieldClass);
                int contextSize = context.size();
                if (fieldType != null) {
                  context.add(fieldType);
                }
                Type subValueType =
                    fieldType != null && Map.class.isAssignableFrom(fieldClass)
                        ? Types.getMapValueParameter(fieldType)
                        : null;
                subValueType = Data.resolveWildcardTypeOrTypeVariable(context, subValueType);
                isStopped =
                    parseElementInternal(
                        parser,
                        context,
                        mapValue,
                        subValueType,
                        namespaceDictionary,
                        customizeParser);
                if (fieldType != null) {
                  context.remove(contextSize);
                }
                if (destinationMap != null) {
                  // map but not GenericXml: store as ArrayList of elements
                  @SuppressWarnings("unchecked")
                  Collection<Object> list = (Collection<Object>) destinationMap.get(fieldName);
                  if (list == null) {
                    list = new ArrayList<Object>(1);
                    destinationMap.put(fieldName, list);
                  }
                  list.add(mapValue);
                } else if (field != null) {
                  // not a map: store in field value
                  FieldInfo fieldInfo = FieldInfo.of(field);
                  if (fieldClass == Object.class) {
                    // field is an Object: store as ArrayList of element maps
                    @SuppressWarnings("unchecked")
                    Collection<Object> list = (Collection<Object>) fieldInfo.getValue(destination);
                    if (list == null) {
                      list = new ArrayList<Object>(1);
                      fieldInfo.setValue(destination, list);
                    }
                    list.add(mapValue);
                  } else {
                    // field is a Map: store as a single element map
                    fieldInfo.setValue(destination, mapValue);
                  }
                } else {
                  // GenericXml: store as ArrayList of elements
                  GenericXml atom = (GenericXml) destination;
                  @SuppressWarnings("unchecked")
                  Collection<Object> list = (Collection<Object>) atom.get(fieldName);
                  if (list == null) {
                    list = new ArrayList<Object>(1);
                    atom.set(fieldName, list);
                  }
                  list.add(mapValue);
                }
              } else if (isArray || Types.isAssignableToOrFrom(fieldClass, Collection.class)) {
                // TODO(yanivi): some duplicate code here; isolate into reusable methods
                FieldInfo fieldInfo = FieldInfo.of(field);
                Object elementValue = null;
                Type subFieldType =
                    isArray
                        ? Types.getArrayComponentType(fieldType)
                        : Types.getIterableParameter(fieldType);
                Class<?> rawArrayComponentType =
                    Types.getRawArrayComponentType(context, subFieldType);
                subFieldType = Data.resolveWildcardTypeOrTypeVariable(context, subFieldType);
                Class<?> subFieldClass =
                    subFieldType instanceof Class<?> ? (Class<?>) subFieldType : null;
                if (subFieldType instanceof ParameterizedType) {
                  subFieldClass = Types.getRawClass((ParameterizedType) subFieldType);
                }
                boolean isSubEnum = subFieldClass != null && subFieldClass.isEnum();
                if (Data.isPrimitive(subFieldType) || isSubEnum) {
                  elementValue = parseTextContentForElement(parser, context, false, subFieldType);
                } else if (subFieldType == null
                    || subFieldClass != null
                        && Types.isAssignableToOrFrom(subFieldClass, Map.class)) {
                  elementValue = Data.newMapInstance(subFieldClass);
                  int contextSize = context.size();
                  if (subFieldType != null) {
                    context.add(subFieldType);
                  }
                  Type subValueType =
                      subFieldType != null && Map.class.isAssignableFrom(subFieldClass)
                          ? Types.getMapValueParameter(subFieldType)
                          : null;
                  subValueType = Data.resolveWildcardTypeOrTypeVariable(context, subValueType);
                  isStopped =
                      parseElementInternal(
                          parser,
                          context,
                          elementValue,
                          subValueType,
                          namespaceDictionary,
                          customizeParser);
                  if (subFieldType != null) {
                    context.remove(contextSize);
                  }
                } else {
                  elementValue = Types.newInstance(rawArrayComponentType);
                  int contextSize = context.size();
                  context.add(fieldType);
                  isStopped =
                      parseElementInternal(
                          parser, context, elementValue, null, namespaceDictionary, customizeParser);
                  context.remove(contextSize);
                }
                if (isArray) {
                  // array field: add new element to array value map
                  if (field == null) {
                    arrayValueMap.put(fieldName, rawArrayComponentType, elementValue);
                  } else {
                    arrayValueMap.put(field, rawArrayComponentType, elementValue);
                  }
                } else {
                  // collection: add new element to collection
                  @SuppressWarnings("unchecked")
                  Collection<Object> collectionValue =
                      (Collection<Object>)
                          (field == null
                              ? destinationMap.get(fieldName)
                              : fieldInfo.getValue(destination));
                  if (collectionValue == null) {
                    collectionValue = Data.newCollectionInstance(fieldType);
                    setValue(
                        collectionValue, field, destination, genericXml, destinationMap, fieldName);
                  }
                  collectionValue.add(elementValue);
                }
              } else {
                // not an array/iterable or a map, but we do have a field
                Object value = Types.newInstance(fieldClass);
                int contextSize = context.size();
                context.add(fieldType);
                isStopped =
                    parseElementInternal(
                        parser, context, value, null, namespaceDictionary, customizeParser);
                context.remove(contextSize);
                setValue(value, field, destination, genericXml, destinationMap, fieldName);
              }
            }
            if (isStopped || parser.getEventType() == XmlPullParser.END_DOCUMENT) {
              isStopped = true;
              break main;
            }
            break; // break Switch;
        } // end -- switch (event)
      } // end -- main: while (true)
      arrayValueMap.setValues();
      return isStopped;
    }