JAXB десортирует недопустимое целое число

В нашем продукте мы используем apache CXF. Из-за ограничения производительности для проверки схемы задано значение false. Теперь для целочисленного элемента, если я предоставляю недопустимое значение, JAXB разбирает его на что-то еще. Например,

9999999999 преобразуется в 1410065407.

988888888888 преобразуется в 1046410808.

Мой вопрос в том, какова логика (формула), которой здесь следуют?

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


person Arnab Biswas    schedule 04.11.2012    source источник


Ответы (1)


Примечание. Я EclipseLink JAXB (MOXy) руководитель и член JAXB (JSR-222) Экспертная группа.

КОРОТКИЙ ОТВЕТ

Похоже, это ошибка в эталонной реализации JAXB. Я бы порекомендовал ввести ошибку для него в следующем месте:

Этот же вариант использования корректно работает в EclipseLink JAXB (MOXy).


ДЛИННЫЙ ОТВЕТ

Ниже приведен полный пример, демонстрирующий проблему:

Корневой

Ниже представлен класс домена с полями int и integer.

package forum13216624;

import javax.xml.bind.annotation.*;

@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class Root {

    int int1;
    int int2;
    Integer integer1;
    Integer integer2;

}

input.xml

Ниже приведен XML-документ со значениями из вашего вопроса.

<?xml version="1.0" encoding="UTF-8"?>
<root>
    <int1>9999999999</int1>
    <int2>988888888888</int2>
    <integer1>9999999999</integer1>
    <integer2>988888888888</integer2>
</root>

Демо

В приведенном ниже демонстрационном коде я указал ValidationEventHandler на Unmarshaller. Это должно поймать ValidationEvent для любых недопустимых значений, обнаруженных во время операции unmarhsal.

package forum13216624;

import java.io.File;
import javax.xml.bind.*;

public class Demo {

    public static void main(String[] args) throws Exception {
        JAXBContext jc = JAXBContext.newInstance(Root.class);

        Unmarshaller unmarshaller = jc.createUnmarshaller();
        unmarshaller.setEventHandler(new ValidationEventHandler() {

            @Override
            public boolean handleEvent(ValidationEvent event) {
                System.out.println(event.getMessage());
                return true;
            }}

        );
        File xml = new File("src/forum13216624/input.xml");
        Root root = (Root) unmarshaller.unmarshal(xml);

        System.out.println(root.int1);
        System.out.println(root.int2);
        System.out.println(root.integer1);
        System.out.println(root.integer2);
    }

}

Выходные данные — эталонная реализация JAXB

Этот вывод соответствует поведению, которое вы видите.

1410065407
1046410808
1410065407
1046410808

Вывод – EclipseLink JAXB (MOXy)

Если вы укажете MOXy в качестве поставщика JAXB (см.: http://blog.bdoughan.com/2011/05/specifying-eclipselink-moxy-as-your.html) этот вариант использования работает, как и ожидалось. Вы получите ValidationEvent для каждого недопустимого значения, и если ValidationEvent будет обработано, для поля/свойства не будет установлено недопустимое значение.

Exception Description: The object [9999999999], of class [class java.lang.String], from mapping [org.eclipse.persistence.oxm.mappings.XMLDirectMapping[int1-->int1/text()]] with descriptor [XMLDescriptor(forum13216624.Root --> [DatabaseTable(root)])], could not be converted to [class java.lang.Integer].
Internal Exception: java.lang.NumberFormatException: For input string: "9999999999"

Exception Description: The object [988888888888], of class [class java.lang.String], from mapping [org.eclipse.persistence.oxm.mappings.XMLDirectMapping[int2-->int2/text()]] with descriptor [XMLDescriptor(forum13216624.Root --> [DatabaseTable(root)])], could not be converted to [class java.lang.Integer].
Internal Exception: java.lang.NumberFormatException: For input string: "988888888888"

Exception Description: The object [9999999999], of class [class java.lang.String], from mapping [org.eclipse.persistence.oxm.mappings.XMLDirectMapping[integer1-->integer1/text()]] with descriptor [XMLDescriptor(forum13216624.Root --> [DatabaseTable(root)])], could not be converted to [class java.lang.Integer].
Internal Exception: java.lang.NumberFormatException: For input string: "9999999999"

Exception Description: The object [988888888888], of class [class java.lang.String], from mapping [org.eclipse.persistence.oxm.mappings.XMLDirectMapping[integer2-->integer2/text()]] with descriptor [XMLDescriptor(forum13216624.Root --> [DatabaseTable(root)])], could not be converted to [class java.lang.Integer].
Internal Exception: java.lang.NumberFormatException: For input string: "988888888888"
0
0
null
null

ВОЗМОЖНОЕ ВРЕМЕННОЕ РЕШЕНИЕ

Если ваши поля/свойства имеют тип Integer и вы можете переключиться с эталонной реализации JAXB, вы можете создать XmlAdapter для выполнения собственных преобразований Integer в/из String.

IntegerAdapter

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

package forum13216624;

import javax.xml.bind.annotation.adapters.XmlAdapter;

public class IntegerAdapter extends XmlAdapter<String, Integer>{

    @Override
    public Integer unmarshal(String string) throws Exception {
        return Integer.valueOf(string);
    }

    @Override
    public String marshal(Integer integer) throws Exception {
        return String.valueOf(integer);
    }

}

информация о пакете

Использование аннотации @XmlJavaTypeAdapter на уровне пакета означает, что XmlAdapter будет применяться ко всем полям/свойствам типа Integer для классов в этом пакете.

@XmlJavaTypeAdapter(value=IntegerAdapter.class, type=Integer.class)
package forum13216624;

import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;

Вывод

Ниже приведены обновленные выходные данные при использовании RI. Значения int по-прежнему неверны, но не значения Integer, а null и ValidationEvents создаются, как ожидалось.

java.lang.NumberFormatException: For input string: "9999999999"
java.lang.NumberFormatException: For input string: "988888888888"
1410065407
1046410808
null
null

Для получения дополнительной информации

person bdoughan    schedule 04.11.2012
comment
Большое спасибо за разъяснение вопроса! Для нашего продукта переключение эталонной реализации JAXB может оказаться невозможным, но объявление элементов типа integer как строки может быть потенциальным решением. - person Arnab Biswas; 04.11.2012
comment
@ArnabBiswas - вам не нужно создавать элементы типа string. Вместо этого я предлагал предоставить вашу собственную логику преобразования String/Integer через файл XmlAdapter. Я обновил свой ответ полным примером. - person bdoughan; 04.11.2012
comment
Спасибо еще раз. Извините, что я не был достаточно ясен в своем комментарии. Но, это то, что я также рассматриваю. - person Arnab Biswas; 04.11.2012
comment
Блейз Доган, ты был прав. Моя концепция адаптера была неправильной. - person Arnab Biswas; 04.11.2012