protected void doMarshal( final Object source, final HierarchicalStreamWriter writer, final MarshallingContext context) { final Set seenFields = new HashSet(); final Set seenAsAttributes = new HashSet(); // Attributes might be preferred to child elements ... reflectionProvider.visitSerializableFields( source, new ReflectionProvider.Visitor() { public void visit(String fieldName, Class type, Class definedIn, Object value) { SingleValueConverter converter = mapper.getConverterFromItemType(fieldName, type, definedIn); if (converter == null) converter = mapper.getConverterFromItemType(fieldName, type); if (converter == null) converter = mapper.getConverterFromItemType(type); if (converter != null) { if (value != null) { final String str = converter.toString(value); if (str != null) { writer.addAttribute(mapper.aliasForAttribute(fieldName), str); } } seenAsAttributes.add(fieldName); } } }); // Child elements not covered already processed as attributes ... reflectionProvider.visitSerializableFields( source, new ReflectionProvider.Visitor() { public void visit(String fieldName, Class fieldType, Class definedIn, Object newObj) { if (!seenAsAttributes.contains(fieldName) && newObj != null) { Mapper.ImplicitCollectionMapping mapping = mapper.getImplicitCollectionDefForFieldName(source.getClass(), fieldName); if (mapping != null) { if (mapping.getItemFieldName() != null) { Collection list = (Collection) newObj; for (Iterator iter = list.iterator(); iter.hasNext(); ) { Object obj = iter.next(); writeField( fieldName, mapping.getItemFieldName(), mapping.getItemType(), definedIn, obj); } } else { context.convertAnother(newObj); } } else { writeField(fieldName, fieldName, fieldType, definedIn, newObj); seenFields.add(fieldName); } } } private void writeField( String fieldName, String aliasName, Class fieldType, Class definedIn, Object newObj) { try { if (!mapper.shouldSerializeMember(definedIn, aliasName)) { return; } ExtendedHierarchicalStreamWriterHelper.startNode( writer, mapper.serializedMember(definedIn, aliasName), fieldType); Class actualType = newObj.getClass(); Class defaultType = mapper.defaultImplementationOf(fieldType); if (!actualType.equals(defaultType)) { String serializedClassName = mapper.serializedClass(actualType); if (!serializedClassName.equals(mapper.serializedClass(defaultType))) { writer.addAttribute(mapper.aliasForSystemAttribute("class"), serializedClassName); } } if (seenFields.contains(aliasName)) { writer.addAttribute( mapper.aliasForAttribute("defined-in"), mapper.serializedClass(definedIn)); } Field field = reflectionProvider.getField(definedIn, fieldName); marshallField(context, newObj, field); writer.endNode(); } catch (RuntimeException e) { // intercept an exception so that the stack trace shows how we end up marshalling the // object in question throw new RuntimeException( "Failed to serialize " + definedIn.getName() + "#" + fieldName + " for " + source.getClass(), e); } } }); }