2010-05-04 6 views
5

En supposant que j'ai un schéma qui décrit une classe d'éléments racine Root qui contient un List<Entry> où la classe Entry a un nom de champ obligatoire.Personnalisation du traitement des erreurs du processus unmarshall de JAXB

Voici à quoi il ressemble dans le code:

@XmlRootElement 
class Root{ 
    @XmlElement(name="entry") 
    public List<Entry> entries = Lists.newArrayList(); 
} 

@XmlRootElement 
class Entry{ 
    @XmlElement(name="name",required=true) 
    public String name; 
} 

Si je fournir le code XML suivant pour unmarshalling:

<root> 
    <entry> 
    <name>ekeren</name> 
    </entry> 
    <entry> 
    </entry> 
</root> 

J'ai un problème parce que la deuxième entrée ne contient pas de nom. Donc, unmarshall produit null.

Y at-il un moyen de personnaliser JAXB à unmarshall un objet Root qui ne contiendra que la "bonne" entrée?

Répondre

5

Vous pouvez ajouter le magic afterUnmarshal method à prendre en charge les entrées vides:

@XmlRootElement 
class Root{ 
    @XmlElement(name="entry") 
    public List<Entry> entries = Lists.newArrayList(); 

    void afterUnmarshal(final Unmarshaller unmarshaller, final Object parent) { 
    Iterator<Entry> iter = entries.iterator(); 
    while (iter.hasNext()) { 
     if (iter.next().name == null) iter.remove(); 
    } 
    } 
} 

EDIT:

Je ne sais pas si cela est mieux pour vous, mais peut-être qu'il est de l'aide. Vous pouvez également utiliser un Pacher, par ex. si tous les objets dont vous avez besoin pour fixer/valider votre résultat sont disponibles dans afterUnmarshal (..)

Exécuté par UnmarshallingContext une fois l'analyse terminée. Principalement utilisé pour résoudre les IDREF en aval, mais il peut exécuter n'importe quelle action. (Javadoc)

Voici un exemple:

@XmlRootElement 
class Entry{ 
    @XmlElement(name="name",required=true) 
    public String name; 

    private boolean isValidEntry() { 
    return name != null; 
    } 

    void afterUnmarshal(final Unmarshaller unmarshaller, final Object parent) { 
    if (!isValidEntry()) { 
     // entry not yet added to parent - use a patcher 
     UnmarshallingContext.getInstance().addPatcher(new Patcher() { 
     public void run() throws SAXException { 
      ((Root)parent).removeEntry(this); 
     } 
     }); 
    } 
    } 
} 

Je n'abuser trop cependant, non seulement il est l'API Sun uniquement. Mais si vous cherchez vraiment quelque chose de configurable qui ne fait pas partie du code des objets assemblés lui-même. Il pourrait être préférable de regarder quelque chose après unmarshalling. Je me demande si Bean Validation (JSR 303) ne serait pas un ajustement parfait pour vous, par ex. en utilisant Hibernate Validator (ne soyez pas intimidé par le nom, vous n'avez pas besoin d'Hibernate ORM pour l'utiliser). Je ne l'ai pas utilisé moi-même, mais l'utilisation d'une (nouvelle) norme pour la validation semble raisonnable, n'est-ce pas?

+0

c'est une bonne idée, merci. Bien sûr, je devrai définir le eventHandler comme tolérant pour l'erreur "field is required" mais cela ne devrait pas poser de problème. Je me demande s'il y a une solution différente, j'essaie de rendre l'utilisateur de mon système (j'écris une lib pour mon groupe qui traite de la configuration) pour pouvoir facilement régler cette fonction. Je peux le faire avec l'annotation et une introspection de classe pour voir tous les champs qui doivent être testés pour le nom requis ... à l'intérieur de afterUnmarshal (...). Je vais garder cela sans réponse peut-être qu'il y a quelqu'un avec une réponse plus appropriée pour ce dont j'ai besoin. – ekeren

+0

@ekeren voir mon édition, j'espère que cela aide. à votre santé – sfussenegger

Questions connexes