Двойное подчеркивание в XStream - обработка в контексте приложения Java Spring Batch

Я использую XStream для Oxm (Java объектов в XML). NameCoder использует символ подчеркивания в качестве escape-символа по умолчанию (подробнее см. Ниже), и поскольку у меня ext_data в качестве тега xml, он записывается как ext__data.

XStream сопоставляет имена классов Java и имена полей с тегами или атрибутами XML. К сожалению, это отображение не может быть 1:1, поскольку некоторые символы, используемые для идентификаторов в Java, недопустимы в именах XML. Поэтому XStream использует anXmlFriendlyNameCoder для замены этих символов заменой. По умолчанию этот NameCoder использует подчеркивание в качестве escape-символа и поэтому должен также экранировать само подчеркивание. Вы можете предоставить другой сконфигурированный экземпляр XmlFriendlyNameCoder или полностью другую реализацию, такую ​​как NoNameCoder, чтобы вообще запретить кодирование имени. Однако вы несете ответственность за то, чтобы полученные имена были действительными для XML. ( http://x-stream.github.io/faq.html)

Я попытался предоставить другой сконфигурированный экземпляр XMLFriendlyNameCoder (используя различные реализации HierarchicalStreamDriver), а также использовать совершенно другую реализацию NoNameCoder. Хотя приложение работает успешно, результаты остаются без изменений. Я использую XStream 1.4.8.

Есть много примеров того, как использовать предложенный обходной путь (вот пара, http://forum.spring.io/forum/spring-projects/batch/74500-getting-double-underscores-in-xml-when-using-staxeventitemwriter, XStream и подчеркивание), поэтому я вполне уверен, что мои различные попытки были настроены правильно (но я мог что-то упустить). Вот моя последняя конфигурация:

<beans:bean id="myMarshaller" class="org.springframework.oxm.xstream.XStreamMarshaller">
    <beans:property name="streamDriver">
        <beans:bean class="com.thoughtworks.xstream.io.xml.Xpp3Driver">
            <beans:constructor-arg>
                <beans:bean class="com.thoughtworks.xstream.io.xml.XmlFriendlyNameCoder">   
                    <beans:constructor-arg index="0" value="DDD"/>
                    <beans:constructor-arg index="1" value="_"/>
                </beans:bean>
            </beans:constructor-arg>
        </beans:bean>
    </beans:property>                       
    <beans:property name="fieldAliases">
    <util:map id="aliases">
            <beans:entry key="com.billup.beans.Data.extData" value="ext_data"/>
        </util:map>
    </beans:property>
</beans:bean>

Я не совсем уверен, но, похоже, проблема в том, что Spring почему-то не принимает эту конфигурацию. Копая org.springframework.oxm.xstream.XStreamMarshaller, похоже, что streamDriver используется только внутри marshalOutputStream (и marshalWriter, вызываемый внутри marshalOutputStream), так что, возможно, я настроил это так, что пользовательская реализация игнорируется и используется streamDriver по умолчанию...

@Override
protected void marshalXmlEventWriter(Object graph, XMLEventWriter eventWriter) throws XmlMappingException {
    ContentHandler contentHandler = StaxUtils.createContentHandler(eventWriter);
    marshalSaxHandlers(graph, contentHandler, null);
}

@Override
protected void marshalXmlStreamWriter(Object graph, XMLStreamWriter streamWriter) throws XmlMappingException {
    try {
        marshal(graph, new StaxWriter(new QNameMap(), streamWriter));
    }
    catch (XMLStreamException ex) {
        throw convertXStreamException(ex, true);
    }
}

@Override
protected void marshalOutputStream(Object graph, OutputStream outputStream) throws XmlMappingException, IOException {
    if (this.streamDriver != null) {
        marshal(graph, this.streamDriver.createWriter(outputStream));
    }
    else {
        marshalWriter(graph, new OutputStreamWriter(outputStream, this.encoding));
    }
}

@Override
protected void marshalSaxHandlers(Object graph, ContentHandler contentHandler, LexicalHandler lexicalHandler)
        throws XmlMappingException {

    SaxWriter saxWriter = new SaxWriter();
    saxWriter.setContentHandler(contentHandler);
    marshal(graph, saxWriter);
}

@Override
protected void marshalWriter(Object graph, Writer writer) throws XmlMappingException, IOException {
    if (this.streamDriver != null) {
        marshal(graph, this.streamDriver.createWriter(writer));
    }
    else {
        marshal(graph, new CompactWriter(writer));
    }
}

/**
 * Marshals the given graph to the given XStream HierarchicalStreamWriter.
 * Converts exceptions using {@link #convertXStreamException}.
 */
private void marshal(Object graph, HierarchicalStreamWriter streamWriter) {
    try {
        getXStream().marshal(graph, streamWriter);
    }
    catch (Exception ex) {
        throw convertXStreamException(ex, true);
    }
    finally {
        try {
            streamWriter.flush();
        }
        catch (Exception ex) {
            logger.debug("Could not flush HierarchicalStreamWriter", ex);
        }
    }
}

Я понимаю, что этот вопрос кажется уникальным и узким по объему, но ответы могут пролить свет на более широкий вопрос о том, как правильно настроить streamDriver в контексте приложения (в приложении Spring Batch).

Примечание. Я использую Spring 4 и Java 8.

Спасибо

Изменить: я также попытался использовать следующую конфигурацию:

<beans:bean id="myMarshaller" class="org.springframework.oxm.xstream.XStreamMarshaller">
    <beans:property name="streamDriver">
        <beans:bean class="com.thoughtworks.xstream.io.xml.DomDriver">
            <beans:constructor-arg value="UTF-8"/>
            <beans:constructor-arg>
                <beans:bean class="com.thoughtworks.xstream.io.naming.NoNameCoder"/>
            </beans:constructor-arg>
        </beans:bean>
    </beans:property>       
    <beans:property name="fieldAliases">
    <util:map id="aliases">
            <beans:entry key="com.billup.beans.Data.extData" value="ext_data"/>
        </util:map>
    </beans:property>
</beans:bean>

1 ответ

Видимо, я поступил об этом неправильно. Ниже, кажется, работает:

<beans:bean id="myMarshaller" class="org.springframework.oxm.xstream.XStreamMarshaller">
    <beans:property name="nameCoder">
        <beans:bean class="com.thoughtworks.xstream.io.xml.XmlFriendlyNameCoder">   
            <beans:constructor-arg index="0" value="_-"/>
            <beans:constructor-arg index="1" value="_"/>
        </beans:bean>
    </beans:property>
    <beans:property name="fieldAliases">
        <util:map id="aliases">
            <beans:entry key="com.billup.beans.Data.extData" value="ext_data"/>
        </util:map>
    </beans:property>
</beans:bean>
Другие вопросы по тегам