Cómo asignar la propiedad unset al valor sin obtener la excepción NullPointerException en Dozer

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

  •  05-07-2019
  •  | 
  •  

Pregunta

Usando Dozer para mapear dos objetos, tengo:

/**
/* 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 no configuro la identificación en la primera clase (llamando a class1.setId ()), el resultado es una excepción NullPointerException de Dozer. Entiendo que esto es correcto ya que get (" id ") sería nulo.

Por supuesto, puedo resolver esto poniendo un cheque para nulo, y devolviendo -1 o 0, o lo que sea.

El problema es que esto se convierte en un error de tiempo de ejecución en lugar de un error de tiempo de compilación. Prefiero resolver esto correctamente.

Ahora he leído en la documentación de Dozer que puede hacer que se omita al hacer un mapa -null = " false " , pero no pude hacer que esto funcione ...

¿Alguna sugerencia?

¿Fue útil?

Solución

Creo que el problema no está en la niveladora, sino en el auto-boxing oculto en tu getter:

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

(Integer) get (" id ") se convierte implícitamente en un int porque el tipo de retorno de tu método es " int " ;.

Esto funcionará en la mayoría de los casos ... EXCEPTO cuando el resultado es nulo, en cuyo caso obtienes una NullPointerException porque un int nunca puede ser nulo.

Esto se traduce en NullPointerExceptions ocultas ... Más información aquí: http: / /www.theserverside.com/blogs/thread.tss?thread_id=41731

Para resolver esto, tienes varias opciones:

  • Si Class1 y Class2 pueden, de hecho, contener una identificación nula, desea modificar a sus captadores / definidores para obtener / establecer enteros en lugar de entradas primitivas.

  • Si Class1 y Class2 nunca deberían contener un ID nulo, y considera que es una clase invariante, puede mantener el tipo int primitivo en el getter / setter y:

    • Asegúrese de que get (" id ") nunca será nulo, inicializándolo en algún valor específico (como 0) en el constructor), y asegurándose de que nada pueda establecerlo en nulo.
    • O decida que getId () devolverá un valor predeterminado si es nulo, y agregue un cheque nulo en el getter como usted dijo.
  • Si Class1 puede tener un ID nulo, pero Class2 puede no tenerlo, debe hacer que los getters y setters de Class1 usen un tipo Integer en lugar de un primitivo int, y debe crear un CustomConverter Dozer que devuelva un valor predeterminado cuando el campo fuente es nulo.

Saludos


[EDITAR] Aquí está el código de prueba que muestra que Dozer ignora los nulos de mapeo cuando se le pide que:

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

}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top