Handling invalid enum values while doing JAXB Unmarshalling

后端 未结 3 1598
野趣味
野趣味 2021-01-02 05:14

My Jaxb has created a Enum class based on the XML schema set up.

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

I am using a SOAP UI to check my web

相关标签:
3条回答
  • 2021-01-02 05:39

    Note: I'm the EclipseLink JAXB (MOXy) lead and a member of the JAXB (JSR-222) expert group.

    By default your JAXB (JSR-222) implementation will not fail on any conversion exceptions. If you are using the JAXB APIs to do the unmarshalling then you can set a ValidationEventHandler to catch any problems. Below is an example.

    Root

    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;
        }
    
    }
    

    Fruit

    package forum12147306;
    
    public enum Fruit {
    
        APPLE, 
        ORANGE;
    
    }
    

    Demo

    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 REFERENCE IMPLEMENTATION

    Unfortunately there appears to be a bug in the JAXB RI as a validation event is not being through for the invalid enum value.

    Not a number: ABC
    

    Work Around

    Write your own XmlAdapter to handle to conversion to/from the Fruit enum:

    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);
            }
        }
    
    }
    

    Fruit

    Use the @XmlJavaTypeAdapter annotation to associate the XmlAdapter with the Fruit enumb.

    package forum12147306;
    
    import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
    
    @XmlJavaTypeAdapter(FruitAdapter.class)
    public enum Fruit {
    
        APPLE, 
        ORANGE;
    
    }
    

    New Output

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

    EclipseLink JAXB (MOXy)

    Using MOXy both validation events are thrown. To specify MOXy as your JAXB provider see: 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)])
    
    0 讨论(0)
  • 2021-01-02 05:49

    Short answer based on original reply. You need to do 2 things

    1. implement custom adapter to raise and exception
    2. add event handler to fail unmarshalling

    Fruit.java defines and uses the adapter

    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);
            }
        }
    }
    

    The event handler for unmarshaller that fails parsing on error - i.e it returns false (you might need to decide when to fail and when not to fail)

        JAXBContext jc = JAXBContext.newInstance(Root.class);
        Unmarshaller unmarshaller = jc.createUnmarshaller();
        unmarshaller.setEventHandler(new ValidationEventHandler() {
            @Override
            public boolean handleEvent(ValidationEvent validationEvent) {
                 return false;
            }
        });
    
    0 讨论(0)
  • 2021-01-02 05:52

    An alternative consists in generating XSD schemas as presented in here: how can i unmarshall in jaxb and enjoy the schema validation without using an explicit schema file.

    Here is the snippet I stole from dolbysurnd:

    import java.io.IOException;
    import java.io.Reader;
    import java.util.ArrayList;
    
    import javax.xml.bind.JAXBContext;
    import javax.xml.bind.JAXBException;
    import javax.xml.bind.SchemaOutputResolver;
    import javax.xml.bind.Unmarshaller;
    import javax.xml.transform.Result;
    import javax.xml.transform.dom.DOMResult;
    import javax.xml.transform.dom.DOMSource;
    import javax.xml.validation.Schema;
    import javax.xml.validation.SchemaFactory;
    
    import org.xml.sax.SAXException;
    
    private static List<DOMResult> generateJaxbSchemas(JAXBContext context) throws IOException {
        final List<DOMResult> domResultList = new ArrayList<>();
        context.generateSchema(new SchemaOutputResolver() {
            @Override
            public Result createOutput(String ns, String file) throws IOException {
                DOMResult domResult = new DOMResult();
                domResult.setSystemId(file);
                domResultList.add(domResult);
                return domResult;
            }
        });
        return domResultList;
    }
    
    private static Unmarshaller createUnmarshaller(JAXBContext context) throws SAXException, IOException, JAXBException {
        Unmarshaller unmarshaller = context.createUnmarshaller();
        List<DOMSource> domSourceList = new ArrayList<>();
        for (DOMResult domResult : generateJaxbSchemas(context)) {
            domSourceList.add(new DOMSource(domResult.getNode()));
        }
        SchemaFactory schemaFactory = SchemaFactory.newInstance("http://www.w3.org/2001/XMLSchema");
        Schema schema = schemaFactory.newSchema(domSourceList.toArray(new DOMSource[0]));
        unmarshaller.setSchema(schema);
        return unmarshaller;
    }
    
    public void unmarshal(JAXBContext context, Reader reader) throws JAXBException, SAXException, IOException {
        Unmarshaller unmarshaller = createUnmarshaller(context);
        Object result = unmarshaller.unmarshal(reader);
    }
    
    0 讨论(0)
提交回复
热议问题