2009-09-10 12 views
1

aide Dozer à la carte deux objets, j'ai:Comment Carte Propriété unset à la valeur sans se NullPointerException dans Dozer

/** 
/* This first class uses the GXT (ExtJS) framework 
**/ 
Class1 extends BaseModelData 
{ 
    public int getId() 
    { 
     return (Integer)get("id"); 
    } 

    public void setId(int id) 
    { 
     set("id", id); 
    } 

    // more properties 
} 

Class2 
{ 
    public int getId() 
    { 
     return id; 
    } 

    public void setId(int id) 
    { 
     this.id = id; 
    } 

    // more properties 
} 

Si je ne mets pas Id dans la première classe (en appelant class1.setId()) le résultat est une exception NullPointerException de Dozer. Je comprends que c'est correct car get ("id") serait nul.

Je peux bien sûr résoudre ceci en mettant une vérification pour null, et en retournant -1 ou 0, ou quoi que ce soit.

Le problème est que cela devient alors une erreur d'exécution plutôt qu'une erreur de compilation. Je préférerais de beaucoup résoudre cela correctement.

Maintenant, j'ai lu dans le Dozer documentation that you can have it skip null by doing map-null="false", mais je ne pouvais pas obtenir ce travail ...

Toutes les suggestions?

Répondre

1

Je crois que le problème est pas dozer, mais dans l'auto-unboxing caché dans votre getter:

public int getId() 
{ 
    return (Integer)get("id"); 
} 

(entier) get ("id") est implicitement jeté dans un entier parce que le type de retour de votre méthode est "int".

Cela fonctionnera dans la plupart des cas ... SAUF lorsque le résultat est nul, auquel cas vous obtenez une exception NullPointerException car un int peut ne jamais être nul.

Il en résulte NullPointerExceptions cachés ... Plus d'infos ici: http://www.theserverside.com/blogs/thread.tss?thread_id=41731

Pour résoudre ce problème, vous avez plusieurs choix:

  • Si Class1 et Class2 peuvent en effet contenir un identifiant nul, vous vouloir modifier vos getters/setters pour obtenir/définir des entiers au lieu des ints primitifs.

  • Si les deux Class1 et Class2 ne doivent jamais contenir un identifiant nul, et vous considérez ceci comme une classe invariant, vous pouvez garder le type primitif int dans le getter/setter et:

    • Assurez-vous get ("id") ne sera jamais nul, en l'initialisant à une valeur spécifique (telle que 0) dans le constructeur), et en s'assurant que rien ne peut le mettre à null.
    • Ou décider que getId() retournera une valeur par défaut si null, et ajouter une vérification nulle dans le getter comme vous l'avez dit.
  • Si Class1 peut avoir un identifiant nul, mais Classe2 ne peut pas, vous devriez avoir des apporteurs de classes 1 et setters utiliser un type entier au lieu d'un int primitif, et vous devez créer un CustomConverter de bulldozer qui retourne une valeur par défaut lorsque le champ source est nul.

Cordialement


[EDIT] Voici le code de test qui montre que Dozer ne l'ignore nulls de cartographie lorsqu'on lui a demandé à:

src/com/test/dozer/Class1.java:

package com.test.dozer; 

import com.extjs.gxt.ui.client.data.BaseModelData; 

public class Class1 extends BaseModelData { 

    // Notice the return type here: "Integer" and *not* int 
    // Returning int throws a NullPointerException when get("id") is null! 
    public Integer getId() { 
     return (Integer) get("id"); 
    } 

    public void setId(Integer id) { 
     set("id", id); 
    } 

} 

src/com/test/dozer/Class2.java:

package com.test.dozer; 

public class Class2 { 

    private int id; 

    public void setId(int id) { 
     this.id = id; 
    } 

    public int getId() { 
     return id; 
    } 
} 

src/dozerMappingFile.xml:

<?xml version="1.0" encoding="UTF-8"?> 
<mappings xmlns="http://dozer.sourceforge.net" 
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
      xsi:schemaLocation="http://dozer.sourceforge.net http://dozer.sourceforge.net/schema/beanmapping.xsd"> 

    <configuration> 
    <stop-on-errors>true</stop-on-errors> 
    <date-format>MM/dd/yyyy HH:mm</date-format><!-- default dateformat will apply to all class maps unless the class mapping explicitly overrides it --> 
    <wildcard>true</wildcard><!-- default wildcard policy that will apply to all class maps unless the class mapping explicitly overrides it --> 
    </configuration> 

    <mapping map-null="false"> 
    <class-a>com.test.dozer.Class1</class-a> 
    <class-b>com.test.dozer.Class2</class-b> 
    </mapping> 

</mappings> 

src/com/te st/dozer/DozerTest.java:

package com.test.dozer; 

import java.util.Arrays; 

import junit.framework.Assert; 

import org.dozer.DozerBeanMapper; 
import org.junit.Before; 
import org.junit.Test; 

public class DozerTest { 

    private DozerBeanMapper mapper; 

    @Before 
    public void setUp() { 
     mapper = new DozerBeanMapper(Arrays.asList("dozerMappingFile.xml")); 
    } 

    /** 
    * Verifies that class1's id is mapped into class2's id when not null. 
    */ 
    @Test 
    public void testMappingWhenIdNotNull() { 
     Class1 class1 = new Class1(); 
     class1.setId(1); 
     Class2 class2 = new Class2(); 
     class2.setId(2); 

     mapper.map(class1, class2); 

     Assert.assertEquals(1, class2.getId()); 
    } 

    /** 
    * Verifies that class2's id is not set to null when class1's id is null. 
    */ 
    @Test 
    public void testMappingWhenIdIsNull() { 
     Class1 class1 = new Class1(); 
     Class2 class2 = new Class2(); 
     class2.setId(2); 

     mapper.map(class1, class2); 

     Assert.assertEquals(2, class2.getId()); 
    } 

} 
+0

Je suis d'accord avec tout ce que vous dites, mais ce que je comprends qu'il est aussi possible d'avoir bulldozer sauter mappings valeurs NULL. De cette façon, le logiciel de cartographie ne mappe pas les champs invalides. –

+1

Il est en effet possible d'avoir des mappings null de Dozer, en utilisant le paramètre map-null = "false". Le problème est que Dozer appellera getId() pour déterminer s'il est nul ou non, et sinon il le mappera. Mais getId() échouera en raison de l'auto-unboxing de null à int ... Si vous remplacez votre getter pour retourner "Integer" au lieu de "int", cela fonctionne. Je vais modifier ma réponse ci-dessus avec le test pour le montrer. –