private Class determineType(
     HierarchicalStreamReader reader,
     boolean validField,
     Object result,
     String fieldName,
     Class definedInCls) {
   String classAttribute = reader.getAttribute(mapper.aliasForAttribute("class"));
   Class fieldType = reflectionProvider.getFieldType(result, fieldName, definedInCls);
   if (classAttribute != null) {
     Class specifiedType = mapper.realClass(classAttribute);
     if (fieldType.isAssignableFrom(specifiedType))
       // make sure that the specified type in XML is compatible with the field type.
       // this allows the code to evolve in more flexible way.
       return specifiedType;
   }
   if (!validField) {
     Class itemType = mapper.getItemTypeForItemFieldName(result.getClass(), fieldName);
     if (itemType != null) {
       return itemType;
     } else {
       return mapper.realClass(reader.getNodeName());
     }
   } else {
     return mapper.defaultImplementationOf(fieldType);
   }
 }
 private Map writeValueToImplicitCollection(
     UnmarshallingContext context,
     Object value,
     Map implicitCollections,
     Object result,
     String itemFieldName) {
   String fieldName =
       mapper.getFieldNameForItemTypeAndName(
           context.getRequiredType(), value.getClass(), itemFieldName);
   if (fieldName != null) {
     if (implicitCollections == null) {
       implicitCollections = new HashMap(); // lazy instantiation
     }
     Collection collection = (Collection) implicitCollections.get(fieldName);
     if (collection == null) {
       Class fieldType =
           mapper.defaultImplementationOf(
               reflectionProvider.getFieldType(result, fieldName, null));
       if (!Collection.class.isAssignableFrom(fieldType)) {
         throw new ObjectAccessException(
             "Field "
                 + fieldName
                 + " of "
                 + result.getClass().getName()
                 + " is configured for an implicit Collection, but field is of type "
                 + fieldType.getName());
       }
       if (pureJavaReflectionProvider == null) {
         pureJavaReflectionProvider = new PureJavaReflectionProvider();
       }
       collection = (Collection) pureJavaReflectionProvider.newInstance(fieldType);
       reflectionProvider.writeField(result, fieldName, collection, null);
       implicitCollections.put(fieldName, collection);
     }
     collection.add(value);
   }
   return implicitCollections;
 }
  public Object doUnmarshal(
      final Object result,
      final HierarchicalStreamReader reader,
      final UnmarshallingContext context) {
    final SeenFields seenFields = new SeenFields();
    Iterator it = reader.getAttributeNames();
    // Remember outermost Saveable encountered, for reporting below
    if (result instanceof Saveable && context.get("Saveable") == null)
      context.put("Saveable", result);

    // Process attributes before recursing into child elements.
    while (it.hasNext()) {
      String attrAlias = (String) it.next();
      String attrName = mapper.attributeForAlias(attrAlias);
      Class classDefiningField = determineWhichClassDefinesField(reader);
      boolean fieldExistsInClass = fieldDefinedInClass(result, attrName);
      if (fieldExistsInClass) {
        Field field = reflectionProvider.getField(result.getClass(), attrName);
        SingleValueConverter converter =
            mapper.getConverterFromAttribute(field.getDeclaringClass(), attrName, field.getType());
        Class type = field.getType();
        if (converter == null) {
          converter = mapper.getConverterFromItemType(type);
        }
        if (converter != null) {
          Object value = converter.fromString(reader.getAttribute(attrAlias));
          if (type.isPrimitive()) {
            type = Primitives.box(type);
          }
          if (value != null && !type.isAssignableFrom(value.getClass())) {
            throw new ConversionException(
                "Cannot convert type " + value.getClass().getName() + " to type " + type.getName());
          }
          reflectionProvider.writeField(result, attrName, value, classDefiningField);
          seenFields.add(classDefiningField, attrName);
        }
      }
    }

    Map implicitCollectionsForCurrentObject = null;
    while (reader.hasMoreChildren()) {
      reader.moveDown();

      try {
        String fieldName = mapper.realMember(result.getClass(), reader.getNodeName());
        boolean implicitCollectionHasSameName =
            mapper.getImplicitCollectionDefForFieldName(result.getClass(), reader.getNodeName())
                != null;

        Class classDefiningField = determineWhichClassDefinesField(reader);
        boolean fieldExistsInClass =
            !implicitCollectionHasSameName && fieldDefinedInClass(result, fieldName);

        Class type =
            determineType(reader, fieldExistsInClass, result, fieldName, classDefiningField);
        final Object value;
        if (fieldExistsInClass) {
          Field field = reflectionProvider.getField(result.getClass(), fieldName);
          value = unmarshalField(context, result, type, field);
          // TODO the reflection provider should have returned the proper field in first place ....
          Class definedType =
              reflectionProvider.getFieldType(result, fieldName, classDefiningField);
          if (!definedType.isPrimitive()) {
            type = definedType;
          }
        } else {
          value = context.convertAnother(result, type);
        }

        if (value != null && !type.isAssignableFrom(value.getClass())) {
          LOGGER.warning(
              "Cannot convert type " + value.getClass().getName() + " to type " + type.getName());
          // behave as if we didn't see this element
        } else {
          if (fieldExistsInClass) {
            reflectionProvider.writeField(result, fieldName, value, classDefiningField);
            seenFields.add(classDefiningField, fieldName);
          } else {
            implicitCollectionsForCurrentObject =
                writeValueToImplicitCollection(
                    context, value, implicitCollectionsForCurrentObject, result, fieldName);
          }
        }
      } catch (NonExistentFieldException e) {
        LOGGER.log(WARNING, "Skipping a non-existent field " + e.getFieldName(), e);
        addErrorInContext(context, e);
      } catch (CannotResolveClassException e) {
        LOGGER.log(WARNING, "Skipping a non-existent type", e);
        addErrorInContext(context, e);
      } catch (LinkageError e) {
        LOGGER.log(WARNING, "Failed to resolve a type", e);
        addErrorInContext(context, e);
      }

      reader.moveUp();
    }

    // Report any class/field errors in Saveable objects
    if (context.get("ReadError") != null && context.get("Saveable") == result) {
      OldDataMonitor.report((Saveable) result, (ArrayList<Throwable>) context.get("ReadError"));
      context.put("ReadError", null);
    }
    return result;
  }