2012-08-27 20 views
7

My Jaxb ha creado una clase Enum basada en la configuración del esquema XML.Manejo de valores enum no válidos mientras se hace JAXB Unmarshalling

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

Estoy usando una interfaz de usuario SOAP para verificar mi servicio web. Dado que se trata de una entrada de forma libre, si doy una fruta incorrecta, diga "Guva" y luego, en lugar de lanzar una excepción, la devuelve como nula después de hacer UnMarshalling.

¿Cómo puedo evitar esto? ¿Debo usar una clase enum personalizada en lugar de una generada JAXB? Por favor, den un ejemplo. es decir,

respecto Sri

Respuesta

17

Nota: soy el EclipseLink JAXB (MOXy) de plomo y un miembro del grupo de expertos JAXB (JSR-222).

De forma predeterminada, la implementación de JAXB (JSR-222) no fallará en las excepciones de conversión. Si está utilizando las API de JAXB para desmarcar, puede configurar un ValidationEventHandler para detectar cualquier problema. A continuación hay un ejemplo.

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; 

} 

Demostración

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 REFERENCIA APLICACIÓN

Desafortunadamente parece que hay un error en el JAXB RI como un evento de validación es no ser a través del valor de enumeración no válido.

Not a number: ABC 

Actividades alrededor

Escriba su propia XmlAdapter para manejar a la conversión a/desde el Fruit enumeración:

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

} 

fruta

Uso del @XmlJavaTypeAdapter anotación para asociar el XmlAdapter con el Fruit enumb.

package forum12147306; 

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

@XmlJavaTypeAdapter(FruitAdapter.class) 
public enum Fruit { 

    APPLE, 
    ORANGE; 

} 

Nueva salida

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

EclipseLink JAXB (moxy)

Usando moxy ambos eventos de validación se tiran. Para especificar MOXy como su proveedor JAXB, consulte: 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

gracias, muchas gracias por el ejemplo detallado. "... parece que hay un error en JAXB": este comportamiento aún existe. Tal vez las enumeraciones no coincidentes no son errores críticos :-) Su 'solución alternativa' funciona bien. Estoy usando este diseño para no-enums también. ¡Realmente grandioso! – datahaki

+0

Blaise Doughan, ¿ha cambiado algo en MOXy desde que publicó esta respuesta? Parece que no puedo obtener MOXy 2.6.2 para activar eventos en valores enum desconocidos en XML o Json. ¿Tengo que usar XmlJavaTypeAdapter con MOXy también? –

+0

¡Y la falla todavía existe en JAXB! Gracias – JIV

1

Respuesta breve basada en la respuesta original. Que tiene que hacer 2 cosas

  1. implementan adaptador personalizado para subir y excepción
  2. Agregar controlador de eventos a fallar unmarshalling

Fruit.java define y utiliza el adaptador

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

El controlador de eventos para unmarshaller que no analiza el error, es decir, devuelve falso (puede que tenga que decidir cuándo fallar y cuando no fallar)

JAXBContext jc = JAXBContext.newInstance(Root.class); 
    Unmarshaller unmarshaller = jc.createUnmarshaller(); 
    unmarshaller.setEventHandler(new ValidationEventHandler() { 
     @Override 
     public boolean handleEvent(ValidationEvent validationEvent) { 
      return false; 
     } 
    }); 
0

Una alternativa consiste en la generación de esquemas XSD tal como se presenta aquí: how can i unmarshall in jaxb and enjoy the schema validation without using an explicit schema file.

Aquí es el fragmento que le robé a 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); 
} 
Cuestiones relacionadas