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 service. Since it is a free form entry, if i give a wrong fruit say "Guva" then instead of throwing an exception it is returning it as null after doing the UnMarshalling.
How can i avoid this? Should i use custom enum class instead of JAXB generated one. Please give some example. i.e.
regards sri
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)])
Short answer based on original reply. You need to do 2 things
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;
}
});
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With