2009-07-21 5 views
20

J'essaye de faire fonctionner JAXB avec une classe groovy, cependant, il semble que ça ne marche pas mais la version java fonctionne. Voici le code ...Comment faire pour que Groovy et JAXB jouent bien ensemble

Voici les scénarios:

Si 2 et 3 sont décommentée il fonctionne très bien.

Si 1 et 4 sont décommenté je reçois:

com.sun.xml.internal.bind.v2.runtime.IllegalAnnotationsException: 
     2 counts of IllegalAnnotationExceptions 
groovy.lang.MetaClass is an interface, and JAXB can't handle interfaces. 

Si 1 et 5 sont décommentée je reçois:

javax.xml.bind.JAXBException: class org.oclc.presentations.simplejaxb.PlayerGroovy 
     nor any of its super class is known to this context. 

Toutes les idées?

Java:

import javax.xml.bind.annotation.XmlRootElement; 

    @XmlRootElement 
    public class Player { 
    } 

Groovy:

import javax.xml.bind.annotation.XmlRootElement 

    @XmlRootElement 
    public class PlayerGroovy { 
    } 

Test:

import org.junit.Test 
    import javax.xml.bind.JAXBContext 
    import javax.xml.bind.Marshaller 
    import org.junit.Assert 

    class PlayerTest { 
     @Test 
     public void testJaXB(){ 
      //1 PlayerGroovy player = new PlayerGroovy() 
      //2 Player player = new Player() 
      StringWriter writer = new StringWriter(); 
      //3 JAXBContext context = JAXBContext.newInstance(Player.class); 
      //4 JAXBContext context = JAXBContext.newInstance(PlayerGroovy.class); 
      //5 JAXBContext context = JAXBContext.newInstance(PlayerGroovy.getClass()); 
      Marshaller m = context.createMarshaller(); 
      m.marshal(player, writer); 
      println(writer) 
      Assert.assertTrue(true) 
     } 
    } 

Répondre

21

décommentant 1 et 4 est la bonne façon de mettre JAXB avec Groovy. La raison pour laquelle cela ne fonctionne pas est que chaque classe Groovy possède une propriété metaClass. JAXB essaye d'exposer ceci comme une propriété de JAXB qui échoue évidemment. Puisque vous ne déclarez pas la propriété metaClass vous-même, il n'est pas possible de l'annoter pour que JAXB l'ignore. Au lieu de cela, définissez XmlAccessType sur NONE. Cette désactivation JAXB auto-découverte des propriétés à exposer en tant qu'éléments XML. Après cela, vous devez déclarer explicitement tous les champs que vous souhaitez exposer.

Exemple:

@XmlAccessorType(XmlAccessType.NONE) 
@XmlRootElement 
public class PlayerGroovy { 
    @XmlAttribute 
    String value 
} 
+3

+1 excellente réponse – skaffman

15

je le même problème tout en exposant un objet GORM Grails. Après avoir recherché la solution affichée ci-dessus, en utilisant @XmlAccessorType(XmlAccessType.NONE), je me suis vite fatigué de marquer tout comme @XmlAttribute.

Je vais avoir beaucoup de succès en utilisant:

@XmlAccessorType(XmlAccessType.FIELD) 
@XmlRootElement 
public class PlayerGroovy { 
    String value 
} 

Voir: XmlAccessType

Merci à la réponse originale pour moi de se lancer dans la bonne direction.

+5

À noter ce effet ce qui est retourné. XmlAccessType.FIELD renvoie la valeur de la "valeur de chaîne" pas de manipulation qui se produit dans les getters et les setters. C'est pourquoi je n'aime pas tellement ça. Mais oui, cela rend les choses moins verbeuses. – Jackie

1

La solution ne semble pas fonctionner sur une sous-classe abstraite. Je pense que c'est parce que le compilateur ne génère pas le code de remplacement getMetaClass. J'ai fini par mimer les étapes de this question comme suit:

@XmlAccessorType(XmlAccessType.NONE) 
package groovy.lang; 

import javax.xml.bind.annotation.XmlAccessType; 
import javax.xml.bind.annotation.XmlAccessorType; 

Oui, il est un peu bizarre. Dans mon cas, je code comme ceci:

package pkg; 
abstract class ScriptMomma extends groovy.lang.Script { 
    // write some nice supporting code here 
} 

Et pour exécuter mes scripts, j'ai:

def config = new org.codehaus.groovy.control.CompilerConfiguration() 
config.scriptBaseClass = 'pkg.ScriptMomma' 
ScriptMomma mine = new GroovyShell(config).evaluate(scriptFile, 'TheOne') 

Je préfère une meilleure solution, mais en ce moment c'est tout ce que j'ai.

+0

Ce code semble également fonctionner, même si je ne suis pas sûr que ce soit vraiment une bonne idée. 'MetaClass MetaClass = new DelegatingMetaClass (Paramètres)' '@ XmlTransient' ' MetaClass getMetaClass() { '' metaClass' ''} – ngreen

Questions connexes