Come mappare la proprietà unset al valore senza ottenere NullPointerException in Dozer

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

  •  05-07-2019
  •  | 
  •  

Domanda

Usando Dozer per mappare due oggetti, ho:

/**
/* 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
}

Se non imposto l'Id nella prima classe (chiamando class1.setId ()) il risultato è una NullPointerException di Dozer. Comprendo che ciò è corretto in quanto get (" id ") sarebbe nullo.

Posso ovviamente risolverlo inserendo un segno di spunta in null e restituendo -1 o 0, o qualsiasi altra cosa.

Il problema è che questo diventa un errore di runtime piuttosto che un errore di compilazione. Preferirei di gran lunga risolverlo correttamente.

Ora ho letto nella la documentazione di Dozer che puoi farlo saltare nullo facendo mappa -null = " false " , ma non sono riuscito a farlo funzionare ...

Qualche suggerimento?

È stato utile?

Soluzione

Credo che il problema non sia nel dozer, ma nell'auto-unboxing nascosto nel tuo getter:

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

(Intero) get (" id ") viene implicitamente inserito in un int perché il tipo di ritorno del tuo metodo è " int " ;.

Questo funzionerà nella maggior parte dei casi ... TRANNE quando il risultato è null, nel qual caso si ottiene una NullPointerException perché un int potrebbe non essere mai nullo.

Ciò si traduce in NullPointerExceptions nascoste ... Maggiori informazioni qui: http: / /www.theserverside.com/blogs/thread.tss?thread_id=41731

Per risolvere questo, hai più scelte:

  • Se Class1 e Class2 possono effettivamente contenere un ID null, si desidera modificare i propri getter / setter per ottenere / impostare numeri interi anziché interi primitivi.

  • Se sia Class1 che Class2 non devono mai contenere un ID null e lo consideri invariante di classe, puoi mantenere il tipo int primitivo nel getter / setter e:

    • Assicurati che get (" id ") non sarà mai nullo, inizializzandolo su un valore specifico (come 0) nel costruttore) e assicurandoti che nulla possa impostarlo su null.
    • Oppure decidi che getId () restituirà un valore predefinito se null e aggiungi un segno di spunta nel getter come hai detto.
  • Se Class1 può avere un ID null, ma Class2 no, è necessario che i getter e i setter di Class1 utilizzino un tipo intero anziché un primitivo int e si dovrebbe creare un CustomConverter dozer che restituisca un valore predefinito quando il il campo sorgente è nullo.

Saluti


[EDIT] Ecco il codice di prova che mostra che Dozer ignora i null della mappatura quando viene richiesto:

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

}
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top