Comment mapper la propriété unset à la valeur sans obtenir NullPointerException dans Dozer

StackOverflow https://stackoverflow.com/questions/1407041

  •  05-07-2019
  •  | 
  •  

Question

En utilisant Dozer pour mapper deux objets, j'ai:

/**
/* 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 spécifie pas l'ID dans la première classe (en appelant class1.setId ()), le résultat est une exception NullPointerException de Dozer. Je comprends que cela est correct, car get ("id") serait nul.

Je peux bien sûr résoudre ce problème en vérifiant la valeur de null et en renvoyant -1 ou 0, ou autre chose.

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 loin résoudre ce problème correctement.

Maintenant, j'ai lu dans la une documentation sur le bulldozer que vous pouvez faire sauter à null en faisant mapper -null = " false " , mais cela n'a pas fonctionné.

Des suggestions?

Était-ce utile?

La solution

Je crois que le problème ne réside pas dans le bulldozer, mais dans le déballage automatique caché dans votre getter:

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

(Integer) get ("id") est implicitement converti en un entier car le type de résultat 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.

Cela se traduit par des 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 fait contenir un identifiant null, vous souhaitez modifier vos getters / setters pour obtenir / définir des entiers au lieu d'ints primitifs.

  • Si Class1 et Class2 ne doivent jamais contenir d'id null, et que vous considérez qu'il s'agit d'un invariant de classe, vous pouvez conserver le type int primitif dans le getter / setter et:

    • Assurez-vous que get ("id") ne sera jamais nul, en l'initialisant à une valeur spécifique (telle que 0 dans le constructeur) et en veillant à ce que rien ne puisse le définir à null.
    • Ou décidez que getId () retournera une valeur par défaut si null, et ajoutez un contrôle nul dans le getter comme vous l'avez dit.
  • Si Class1 peut avoir un identifiant null, mais que Class2 ne le puisse pas, vous devez faire en sorte que les getters et les régleurs de Class1 utilisent un type Integer au lieu d'une primitive int et vous devez créer un dozer CustomConverter qui renvoie une valeur par défaut lorsque le champ source est nul.

Cordialement

[EDIT] Voici le code de test qui montre que Dozer ignore les correspondances nulles du mappage lorsqu'il est invité à:

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 / test / 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());
    }

}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top