Add possibility to add DOCTYPE element
I found no easy way of adding a DTD to the XML output. E.g.:
<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE gsafeed PUBLIC "-//Google//DTD GSA Feeds//EN" "">
<gsafeed>
...
</gsafeed>
It would be nice to have a feature to add such elements.
Updating, unfortunately did not have time to implement for 2.7.
Hi! Did you find a way to solve this?
No solution yet. Problem mostly related to how to expose this through API: while XmlMapper can add methods that does not allow per-call config settings unlike ObjectWriter -- and latter is not designed to be extensible. Most format-specific additions are either simple on/off "Feature" settings (which can be toggled via ObjectReader / ObjectWriter) or per-mapper settings.
But I still hope to think of a good mechanism, now that 2.11.0 was released and I plan to spend time on XML module too (there are so many Jackson modules, improvement ideas... and so little time to spent on unpaid hobby).
Thanks for your reply and I appreciate your effort. I managed to solve my issue by converting the object to string and then appending the DTD.
@tudordascalu Ok I am glad you have a work-around, and maybe others can use it in the meantime as well. I will keep this open hoping it can be resolved in a better way eventually.
Thanks for your reply and I appreciate your effort. I managed to solve my issue by converting the object to string and then appending the DTD.
I try to lookup a way to achieve it, but failed. I'm not sure whether the way meet your expection. For reference, I achieve it in the following way in version 2.11.1.
import java.util.List;
public interface XmlDocument {
List<String> headers();
}
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.dataformat.xml.ser.XmlBeanSerializer;
import java.io.IOException;
public class XmlDocumentSerializer extends JsonSerializer<XmlDocument> {
private final XmlBeanSerializer defaultSerializer;
public XmlDocumentSerializer(XmlBeanSerializer defaultSerializer) {
this.defaultSerializer = defaultSerializer;
}
@Override
public void serialize(XmlDocument src, JsonGenerator gen,
SerializerProvider serializerProvider) throws IOException {
if (src.headers() == null || src.headers().isEmpty()) {
defaultSerializer.serialize(src, gen, serializerProvider);
return;
}
boolean pretty = serializerProvider.isEnabled(SerializationFeature.INDENT_OUTPUT);
StringBuilder builder = new StringBuilder();
for (String header : src.headers()) {
builder.append(header);
if (pretty) {
builder.append("\n");
}
}
gen.writeRaw(builder.toString());
defaultSerializer.serialize(src, gen, serializerProvider);
}
}
import com.fasterxml.jackson.databind.BeanDescription;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializationConfig;
import com.fasterxml.jackson.databind.ser.BeanSerializerModifier;
import com.fasterxml.jackson.databind.ser.std.BeanSerializerBase;
import com.fasterxml.jackson.dataformat.xml.ser.XmlBeanSerializer;
public class XmlDocumentSerializerModifier extends BeanSerializerModifier {
@Override
public JsonSerializer<?> modifySerializer(SerializationConfig config, BeanDescription beanDesc, JsonSerializer<?> serializer) {
if (!(serializer instanceof BeanSerializerBase)) {
return serializer;
}
XmlBeanSerializer defaultSerializer = new XmlBeanSerializer((BeanSerializerBase) serializer);
if (XmlDocument.class.isAssignableFrom(beanDesc.getBeanClass())) {
return new XmlDocumentSerializer(defaultSerializer);
}
return defaultSerializer;
}
}
public class ExampleXml implements XmlDocument {
@Override
public List<String> headers() {
return Arrays.asList("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>",
"<!DOCTYPE SYSTEM \"any\">");
}
}
public static void main() {
JacksonXmlModule module = new JacksonXmlModule();
module.setSerializerModifier(new XmlDocumentSerializerModifier());
XmlMapper xmlMapper = new XmlMapper(module);
xmlMapper.writeValueAsString(new ExampleXml());
// got expected DOCTYPE
}
Been looking for how to do this as well, and arrived here after following the stackoverflow question that was opened over 5 years ago.
Seems like quite the missing feature after all these years. There are use cases where you need or want to append a custom header, either via the serializer or via annotation to the pojo so when it gets processed it uses that.
@skyhirider I'd recommend adding your "vote" on thumbs-up on description: that can help indicate desire by users. Does not solve the issue of there not being enough contributors/time by contributors but helps finding "most-wanted" issues (I add label when it seems something is highly requested).
@cowtowncoder thanks, just did that. Sorry if the comment was too active, just wanted to highlight the issue. Appreciate all the work that goes into this library just starting to learn and use it.
@skyhirider no problem -- appreciate the interest. And I agree that this would be a good feature to get, was hoping to have time to get it in 2.12 but ended up running out of time (there were tons of other fixes for xml module). Now hoping it could make it in 2.13, as part of mechanism that would solve a few other similar issues (and being flexible enough wrt all aspects of DOCTYPE declaration).