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 преобразувания.

Integer Adapter

По-долу е даден пример за 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
Blaise Doughan - ти беше прав. Концепцията ми за адаптера не беше правилна. - person Arnab Biswas; 04.11.2012