public String toXmlPartial(Object domainObject) {
        bombIf(!isAnnotationPresent(domainObject.getClass(), ConfigTag.class), () -> "Object " + domainObject + " does not have a ConfigTag");
        Element element = elementFor(domainObject.getClass());
        write(domainObject, element, configCache, registry);
        if (isAnnotationPresent(domainObject.getClass(), ConfigCollection.class) && domainObject instanceof Collection) {
            for (Object item : (Collection<?>) domainObject) {
                if (isAnnotationPresent(item.getClass(), ConfigCollection.class) && item instanceof Collection) {
                    new ExplicitCollectionXmlFieldWithValue(domainObject.getClass(), null, (Collection<?>) item, configCache, registry).populate(element);
                    continue;
                }
                Element childElement = elementFor(item.getClass());
                element.addContent(childElement);
                write(item, childElement, configCache, registry);
            }
        }

        try (ByteArrayOutputStream output = new ByteArrayOutputStream(32 * 1024)) {
            XmlUtils.writeXml(element, output);
            // FIXME the lack of charset here looks rather suspicious. But unclear how to fix without possible regressions.
            // Related to similar issue in GoConfigMigration?
            return output.toString();
        } catch (IOException e) {
            throw bomb("Unable to write xml to String");
        }
    }
@Test
    public void shouldWriteEmptyOnCancelTaskWhenDefined() throws Exception {
        String partial = """
                <job name="functional">
                  <tasks>
                    <exec command="echo">
                      <oncancel />
                    </exec>
                  </tasks>
                </job>""";
        JobConfig jobConfig = xmlLoader.fromXmlPartial(partial, JobConfig.class);
        assertThat(xmlWriter.toXmlPartial(jobConfig), is(partial));
    }