2012-05-29 1 views
1

Аналогичный вопрос здесь, и я действительно пытался использовать преобразователи, как следует из ответа.Использование XStream и JsonHierarchicalStreamDriver для вывода значений, как мне удвоить?

Formatting decimal values for XML

Я сериализации объектов в XML как и JSON. Я использую XStream и JsonHierarchicalStreamDriver, когда это необходимо.

Объекты имеют свойства типа double. Это было прекрасно. В XML это сериализовать:

<value>3.14159265</value> 

В JSON это было:

value: 3.14159265 

теперь у меня есть требование, чтобы округлить значение заданного числа знаков после запятой.

С моей первой попытки я написал конвертер, который округлял все удваивает до двух знаков после запятой. Это отображается как указано выше (кроме значения округлено), но проблема в том, что различные свойства нужно округлять до разных значащих цифр, а конвертер не знает, сколько десятичных знаков, когда при методе «маршал».

Моя вторая попытка использует специальный объект для замены двойника, который содержит двойной объект и число десятичных знаков. Требуется другой конвертер, и это хорошо работает для xml, но в json оно отображает значение как строку (т. Е. В кавычках) не как число (это то, что я действительно хочу).

Как визуализировать округленный двойной номер?

Благодаря

+0

быстрый просмотр учебника по конвертерам xstream показывает этот пример: «@XStreamConverter (значение = BooleanConverter.class, booleans = {false}, строки = {« да »,« нет »})». поэтому, похоже, вы можете дать некоторые дополнительные параметры конвертеру. можете ли вы их использовать? –

+0

@DenisTulskiy спасибо, но каждый экземпляр может иметь разное количество знаков после запятой. Если бы был способ передачи текущего объекта или текущего «числа десятичных знаков» в конвертер, это решило бы мою проблему ... – zod

+0

Я думаю, что эта задача намного превосходит то, что могла бы сделать любая библиотека для сортировки. –

ответ

0

Если кому-то интересно, то кажется, что JsonHierarchicalStreamDriver использует класс, называемый JsonWriter. Между ними они берут на себя все, что удваивает, целые и т. Д. Переводят на номер JSON, тогда как пользовательские объекты будут переведены как текст (т. Е. Будут заключены в кавычки). Похоже, что не указано, как вы хотите, чтобы отображалось значение.

Существует несколько вариантов, если вам все еще нужно. Возможно, вы сможете использовать альтернативу JsonHierarchicalStreamDriver. Документация подразумевает, что версия JettisonMappedXmlDriver превратит все числа, подобные строкам, в номера JSON (не всегда желательно).

Я пошел со следующим грязного хака:

Создать новый писатель, который позволяет отказаться от цитаты:

public static class HackJsonWriter extends JsonWriter { 
    public HackJsonWriter(Writer writer) { 
     super(writer); 
    } 

    private boolean dropQuotes = false; 

    public void dropQuotes() { 
     dropQuotes = true; 
    } 

    public void allowQuotes() { 
     dropQuotes = false; 
    } 

    @Override 
    protected void addValue(String value, AbstractJsonWriter.Type type) 
    { 
     if (dropQuotes) { 
      super.addValue(value, AbstractJsonWriter.Type.NULL); 
     } 
     else { 
      super.addValue(value, type); 
     } 
    } 
} 

Перезапишите создание писателя следующим образом:

new XStream(new JsonHierarchicalStreamDriver() { 
    @Override 
    public HierarchicalStreamWriter createWriter(Writer writer) { 
     return new HackJsonWriter(writer); 
    } 
}); 

Создайте конвертер, который видит хак и обрабатывает его.

public static class HackRoundedDoubleConverter implements Converter { 

    private HackRoundedDoubleConverter() { 
    } 

    @Override 
    public boolean canConvert(Class clazz) { 
     return RoundedDouble.class.isAssignableFrom(clazz); 
    } 

    @Override 
    public void marshal(Object value, HierarchicalStreamWriter writer, MarshallingContext context) { 
     if (value == null) { 
      return; // now that i think about it, this should probably write "null" (no quotes), but I was handling that elsewhere 
     } 
     RoundedDouble number = (RoundedDouble)value; 
     if (Double.isNaN(number.getValue()) || Double.isInfinite(number.getValue())) { 
      return; // at this point, we would have a problem. an empty node will be created no matter what (and it translates to an empty object in javascript). 
     } 

     if (writer.underlyingWriter() instanceof HackJsonWriter) { 
      HackJsonWriter hackWriter = (HackJsonWriter)writer.underlyingWriter(); 
      hackWriter.dropQuotes(); 
      writer.setValue(number.getRoundedValue()); 
      hackWriter.allowQuotes(); 
     } 
     else { 
      writer.setValue(number.getRoundedValue()); 
     } 
    } 

    @Override 
    public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) { 
     // only interested in the one direction 
     return null; 
    } 
} 

Регистрация конвертер:

xstream.registerConverter(new HackRoundedDoubleConverter()); 

RoundedDouble это класс, который имеет два свойства, двойное значение, и количество знаков после запятой.

Как я уже сказал, это хак (он очень хрупок и, вероятно, имеет много проблем, которые я даже не заметил), и я, вероятно, нарушил закон при разработке того, как это сделать. Я, вероятно, даже не буду использовать его, но он отвечает на мой первоначальный вопрос.