> This is by design and not something I would want to change.
That's fair.
The application I'm migrating sort of "stitches" new xml documents out of existing ones. Suppose the two following documents
<?xml>
<BucketList>
<Goal id="wealth">Earn a million</Goal>
<Goal id="health">Live to 100</Goal>
</BucketList>
<?xml>
<BucketList>
<Goal id="travel">Visit Canada</Goal>
<Goal id="nature">Build a park</Goal>
</BucketList>
The application gets list of ids that it should match between existing documents to produce a new output. There's a process in place that extracts the "stitchable" elements, so the application just queries that. Suppose input of IDs is "travel" and "health", so result document shall be as follows
<?xml>
<BucketList>
<Goal id="travel">Visit Canada</Goal>
<Goal id="health">Live to 100</Goal>
</BucketList>
These are very simplified documents that I'm using as an example. Yes, for this particular example I could use JAXB to parse each goal into an object and build a new collection, and serialize that.
In reality the structure is unstable. The equivalent Goal element can have either text content or multiple other elements under it, kind of how HTML works. This is mostly due to poor versioning practices, and never having
defined a schema for the documents. In addition, there are multiple versions of the structure out in the wild that we are expected to support at the same time. A closer example of first document would be as follows
<?xml>
<BucketList>
<Goal id="wealth">Earn a million</Goal>
<Goal id="health">
<LifeExpectency>100</LifeExpectency>
</Goal>
</BucketList>
And the final result should be
<?xml>
<BucketList>
<Goal id="travel">Visit Canada</Goal>
<Goal id="health">
<LifeExpectency>100</LifeExpectency>
</Goal>
</BucketList>
As a result, I've also opted to also query the system in place that has all the "stitchable" parts to get them as strings, and then only define BucketList element which has text content field via JAXB. I join the records using Collectors#joining(String, String, String) collector, and wallah. I've replicated the behavior of original system
From your response I understand I've misdirected you. The original intention was to use only one OutputFactory (as this functionality is only part of the application, the other parts that build XML documents are *fairly* consistent, so I could define JAXB equivalent classes), but as per my comment I found that the writer config is global and would affect all serializations, which isn't ideal as some containers expect escaped XML. So my next idea was to somehow bridge the two output factories using XMLAdapter feature provided by JAXB. Sadly, as per my comment, I couldn't figure out how to bridge the two and instead opted to choose one of the two factories and depending on annotations of classes I need to serialize.
void serialize(Object target, Class<?> type, OutputStream outputStream) throws JAXBException, XMLStreamException {
Marshaller marshaller = jaxbContext.createMarshaller();
XMLStreamWriter writer;
if (type.getAnnotation(InlineRawXml.class) == null) { // assert if there's special annotation on container that expects unescaped xml in output
writer = outputFactory.createXMLStreamWriter(outputStream); // use the safe factory if there isn't one
} else {
writer = unescapedOutputFactory.createXMLStreamWriter(outputStream); // use the unsafe factory if there is one
}
String qNameKey = type.getName();
Class adapted = type; // remove generic information to prevent compiler from complaining
QName qName = this.qnameConfigs.get(qNameKey); // query prebuilt cache of qnames
JAXBElement<Object> jaxbElement = new JAXBElement<>(qName, adapted, target); // wrap the object into jaxb element because there can be multiple roots
marshaller.marshal(jaxbElement, writer);
}
Of course the final function handwaves a lot of detail such as how JAXBContext, the qname cache and etc. are built.
I am aware this is stupid approach, but this was my attempt to bring in some structural stability in a process that used to manipulate XML Strings directly on output stream.