in core/src/main/java/hudson/util/RobustReflectionConverter.java [186:260]
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 (Object obj : list) {
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);
}
}
});
}