Skip to content

Commit

Permalink
Start work on #324
Browse files Browse the repository at this point in the history
  • Loading branch information
cowtowncoder committed Jan 31, 2024
1 parent 2ecbbcf commit 74cde13
Show file tree
Hide file tree
Showing 3 changed files with 108 additions and 20 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@ public XmlTypeResolverBuilder(JsonTypeInfo.Value settings) {
@Override
public StdTypeResolverBuilder init(JsonTypeInfo.Id idType, TypeIdResolver idRes)
{

super.init(idType, idRes);
if (_typeProperty != null) {
_typeProperty = StaxUtil.sanitizeXmlTypeName(_typeProperty);
Expand Down Expand Up @@ -138,6 +137,8 @@ protected static String decodeXmlClassName(String className)
protected static class XmlClassNameIdResolver
extends ClassNameIdResolver
{
private static final long serialVersionUID = 1L;

public XmlClassNameIdResolver(JavaType baseType, TypeFactory typeFactory,
PolymorphicTypeValidator ptv)
{
Expand All @@ -159,6 +160,8 @@ public JavaType typeFromId(DatabindContext context, String id) throws IOExceptio
protected static class XmlMinimalClassNameIdResolver
extends MinimalClassNameIdResolver
{
private static final long serialVersionUID = 1L;

public XmlMinimalClassNameIdResolver(JavaType baseType, TypeFactory typeFactory,
PolymorphicTypeValidator ptv)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,19 @@ public enum Feature implements FormatFeature
* @since 2.13
*/
UNWRAP_ROOT_OBJECT_NODE(false),

/**
* Feature that enables automatic conversion of logical property
* name {@code "xsi:type"} into matching XML name where "type"
* is the local name and "xsi" prefix is bound to URI
* {@link XMLConstants#W3C_XML_SCHEMA_INSTANCE_NS_URI},
* and output is indicated to be done as XML Attribute.
* This is mostly desirable for Polymorphic handling where it is difficult
* to specify XML Namespace for type identifier
*
* @since 2.17
*/
AUTO_DETECT_XSI_TYPE(false),
;

final boolean _defaultState;
Expand Down Expand Up @@ -247,20 +260,26 @@ public void initGenerator() throws IOException
}
_initialized = true;
try {
boolean xmlDeclWritten;
if (Feature.WRITE_XML_1_1.enabledIn(_formatFeatures)) {
_xmlWriter.writeStartDocument("UTF-8", "1.1");
xmlDeclWritten = true;
} else if (Feature.WRITE_XML_DECLARATION.enabledIn(_formatFeatures)) {
_xmlWriter.writeStartDocument("UTF-8", "1.0");
xmlDeclWritten = true;
} else {
return;
xmlDeclWritten = false;
}
// as per [dataformat-xml#172], try adding indentation
if (_xmlPrettyPrinter != null) {
if (xmlDeclWritten && (_xmlPrettyPrinter != null)) {
// ... but only if it is likely to succeed:
if (!_stax2Emulation) {
_xmlPrettyPrinter.writePrologLinefeed(_xmlWriter);
}
}
if (Feature.AUTO_DETECT_XSI_TYPE.enabledIn(_formatFeatures)) {
_xmlWriter.setPrefix("xsi", XMLConstants.W3C_XML_SCHEMA_INSTANCE_NS_URI);
}
} catch (XMLStreamException e) {
StaxUtil.throwAsGenerationException(e, this);
}
Expand Down Expand Up @@ -487,23 +506,35 @@ public void writeRepeatedFieldName() throws IOException
/* JsonGenerator method overrides
/**********************************************************
*/

/* Most overrides in this section are just to make methods final,
* to allow better inlining...
*/

@Override
public void writeFieldName(SerializableString name) throws IOException
{
writeFieldName(name.getValue());
}

@Override
public final void writeFieldName(String name) throws IOException
{
if (_writeContext.writeFieldName(name) == JsonWriteContext.STATUS_EXPECT_VALUE) {
_reportError("Can not write a field name, expecting a value");
}
// Should this ever get called?
String ns = (_nextName == null) ? "" : _nextName.getNamespaceURI();
_nameToEncode.namespace = ns;
_nameToEncode.localPart = name;
_nameProcessor.encodeName(_nameToEncode);
setNextName(new QName(_nameToEncode.namespace, _nameToEncode.localPart));

String ns;
// 30-Jan-2024, tatu: Surprise!
if (Feature.AUTO_DETECT_XSI_TYPE.enabledIn(_formatFeatures)
&& "xsi:type".equals(name)) {
setNextName(new QName(XMLConstants.W3C_XML_SCHEMA_INSTANCE_NS_URI,
"type", "xsi"));
setNextIsAttribute(true);
} else {
// Should this ever get called?
ns = (_nextName == null) ? "" : _nextName.getNamespaceURI();
_nameToEncode.namespace = ns;
_nameToEncode.localPart = name;
_nameProcessor.encodeName(_nameToEncode);
setNextName(new QName(_nameToEncode.namespace, _nameToEncode.localPart));
}
}

@Override
Expand All @@ -519,7 +550,7 @@ public final void writeStringField(String fieldName, String value) throws IOExce
// handling...
//
// See [dataformat-xml#4] for more context.

/*
// @since 2.9
public WritableTypeId writeTypePrefix(WritableTypeId typeIdDef) throws IOException
Expand Down Expand Up @@ -640,12 +671,6 @@ public final void _handleEndObject() throws IOException
/**********************************************************
*/

@Override
public void writeFieldName(SerializableString name) throws IOException
{
writeFieldName(name.getValue());
}

@Override
public void writeString(String text) throws IOException
{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package com.fasterxml.jackson.dataformat.xml.ser;

import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonRootName;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.annotation.JsonTypeInfo.As;
import com.fasterxml.jackson.annotation.JsonTypeInfo.Id;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
import com.fasterxml.jackson.dataformat.xml.XmlTestBase;

// [dataformat-xml#324]
public class XsiTypeWriteTest extends XmlTestBase
{
@JsonRootName("Typed")
static class TypeBean {
@JsonProperty("xsi:type")
public String typeId = "abc";
}

@JsonRootName("Poly")
@JsonTypeInfo(use = Id.SIMPLE_NAME, include = As.PROPERTY, property="xsi:type")
static class PolyBean {
public int value = 42;
}

private final XmlMapper NO_XSI_MAPPER = XmlMapper.builder()
.configure(ToXmlGenerator.Feature.AUTO_DETECT_XSI_TYPE, false)
.build();

private final XmlMapper XSI_ENABLED_MAPPER = XmlMapper.builder()
.configure(ToXmlGenerator.Feature.AUTO_DETECT_XSI_TYPE, true)
.build();

public void testExplicitXsiTypeWriteDisabled() throws Exception
{
assertEquals("<Typed><xsi:type>abc</xsi:type></Typed>",
NO_XSI_MAPPER.writeValueAsString(new TypeBean()));
}

public void testExplicitXsiTypeWriteEnabled() throws Exception
{
assertEquals(
a2q("<Typed xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' xsi:type='abc'/>"),
a2q(XSI_ENABLED_MAPPER.writeValueAsString(new TypeBean())));
}

public void testXsiTypeAsTypeIdWriteDisabled() throws Exception
{
assertEquals("<Poly><xsi_type>abc</xsi_type><value>42</value></Poly>",
NO_XSI_MAPPER.writeValueAsString(new PolyBean()));
}

public void testXsiTypeAsTypeIdWriteEnabled() throws Exception
{
assertEquals(
a2q("<Poly xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' xsi:type='abc'>"
+"<value>42</value></Poly>"),
a2q(XSI_ENABLED_MAPPER.writeValueAsString(new PolyBean())));
}
}

0 comments on commit 74cde13

Please sign in to comment.