10

私の Jaxb は、XML スキーマのセットアップに基づいて Enum クラスを作成しました。

**enum Fruit {
    APPLE,ORANGE;
}**

SOAP UI を使用して Web サービスをチェックしています。これは自由形式のエントリであるため、間違った果物に「Guva」と言うと、例外をスローする代わりに、UnMarshalling を実行した後に null として返されます。

どうすればこれを回避できますか? JAXB で生成されたものではなく、カスタム列挙型クラスを使用する必要があります。例を挙げてください。すなわち

よろしく

4

3 に答える 3

20

注: 私はEclipseLink JAXB(MOXy)のリーダーであり、JAXB(JSR-222)エキスパートグループのメンバーです。

デフォルトでは、JAXB(JSR-222)実装は変換例外で失敗しません。JAXB APIを使用してアンマーシャリングを実行している場合は、ValidationEventHandler問題をキャッチするようにを設定できます。以下に例を示します。

package forum12147306;

import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement
public class Root {

    private int number;
    private Fruit fruit;

    public int getNumber() {
        return number;
    }

    public void setNumber(int number) {
        this.number = number;
    }

    public Fruit getFruit() {
        return fruit;
    }

    public void setFruit(Fruit fruit) {
        this.fruit = fruit;
    }

}

フルーツ

package forum12147306;

public enum Fruit {

    APPLE, 
    ORANGE;

}

デモ

package forum12147306;

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

public class Demo {

    private static final String XML = "<root><number>ABC</number><fruit>Guva</fruit></root>";
    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 validationEvent) {
                 System.out.println(validationEvent.getMessage());
                 //validationEvent.getLinkedException().printStackTrace();
                 return true;
            }

        });

        Root root = (Root) unmarshaller.unmarshal(new StringReader(XML));
    }

}

JAXBリファレンス実装

残念ながら、無効な列挙値の検証イベントが実行されていないため、JAXBRIにバグがあるようです。

Not a number: ABC

回避策

列挙型への/列挙型XmlAdapterからの変換を処理するために独自のものを作成します。Fruit

FruitAdapter

package forum12147306;

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

public class FruitAdapter extends XmlAdapter<String, Fruit> {

    @Override
    public String marshal(Fruit fruit) throws Exception {
        return fruit.name();
    }

    @Override
    public Fruit unmarshal(String string) throws Exception {
        try {
            return Fruit.valueOf(string);
        } catch(Exception e) {
            throw new JAXBException(e);
        }
    }

}

フルーツ

@XmlJavaTypeAdapterアノテーションを使用しXmlAdapterて、をFruitenumbに関連付けます。

package forum12147306;

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

@XmlJavaTypeAdapter(FruitAdapter.class)
public enum Fruit {

    APPLE, 
    ORANGE;

}

新しい出力

Not a number: ABC
javax.xml.bind.JAXBException
 - with linked exception:
[java.lang.IllegalArgumentException: No enum const class forum12147306.Fruit.Guva]

EclipseLink JAXB(MOXy)

MOXyを使用すると、両方の検証イベントがスローされます。JAXBプロバイダーとしてMOXyを指定するには、http://blog.bdoughan.com/2011/05/specifying-eclipselink-moxy-as-your.htmlを参照して ください

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

Exception Description: No conversion value provided for the value [Guva] in field [fruit/text()].
Mapping: org.eclipse.persistence.oxm.mappings.XMLDirectMapping[fruit-->fruit/text()]
Descriptor: XMLDescriptor(forum12147306.Root --> [DatabaseTable(root)])
于 2012-08-27T19:16:50.800 に答える
2

元の返信に基づく短い回答。あなたは2つのことをする必要があります

  1. 例外を発生させるカスタムアダプターを実装する
  2. アンマーシャリングを失敗させるイベント ハンドラを追加する

Fruit.javaはアダプタを定義して使用します

package forum12147306;

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

@XmlJavaTypeAdapter(FruitAdapter.class)
public enum Fruit {

    APPLE, 
    ORANGE;

}

class FruitAdapter extends XmlAdapter<String, Fruit> {

    @Override
    public String marshal(Fruit fruit) throws Exception {
        return fruit.name();
    }

    @Override
    public Fruit unmarshal(String string) throws Exception {
        try {
            return Fruit.valueOf(string);
        } catch(Exception e) {
            throw new JAXBException(e);
        }
    }
}

エラー時に解析に失敗する unmarshaller のイベント ハンドラー - つまり、falseを返します(いつ失敗し、いつ失敗しないかを決定する必要がある場合があります)。

    JAXBContext jc = JAXBContext.newInstance(Root.class);
    Unmarshaller unmarshaller = jc.createUnmarshaller();
    unmarshaller.setEventHandler(new ValidationEventHandler() {
        @Override
        public boolean handleEvent(ValidationEvent validationEvent) {
             return false;
        }
    });
于 2014-05-30T15:40:48.573 に答える