¿Es posible en Java para comprobar si los campos de objetos son nulos y luego añadir valor por defecto a todos esos atributos?

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

  •  23-09-2019
  •  | 
  •  

Pregunta

Me necesita para asegurarse de que ningún atributo de objeto es nulo y añadir valor predeterminado en caso si es nulo. ¿Hay alguna forma fácil de hacer esto, o tengo que hacerlo manualmente mediante la comprobación de todos los atributos de sus captadores y definidores?

¿Fue útil?

Solución

Se puede utilizar la reflexión para iterar sobre el campo del objeto, y nos ha salvado. Es obvio que necesitaría algún tipo de correlación entre tipos de nombres de campo o incluso y los valores predeterminados necesarios, pero esto se puede hacer con bastante facilidad en un bucle. Por ejemplo:

for (Field f : obj.getClass().getFields()) {
  f.setAccessible(true);
  if (f.get(obj) == null) {
     f.set(obj, getDefaultValueForType(f.getType()));
  }
}

[Actualización]

Con Java moderna, puede utilizar las anotaciones para establecer los valores predeterminados de los campos en una base por clase. Una implementación completa podría tener este aspecto:

// DefaultString.java:
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

@Retention(RetentionPolicy.RUNTIME)
public @interface DefaultString {
    String value();
}

// DefaultInteger.java:
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

@Retention(RetentionPolicy.RUNTIME)
public @interface DefaultInteger {
    int value();
}

// DefaultPojo.java:
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;

public class DefaultPojo {

    public void setDefaults() {
        for (Field f : getClass().getFields()) {
            f.setAccessible(true);
            try {
                if (f.get(this) == null) {
                    f.set(this, getDefaultValueFromAnnotation(f.getAnnotations()));
                }
            } catch (IllegalAccessException e) { // shouldn't happen because I used setAccessible
            }
        }
    }

    private Object getDefaultValueFromAnnotation(Annotation[] annotations) {
        for (Annotation a : annotations) {
            if (a instanceof DefaultString)
                return ((DefaultString)a).value();
            if (a instanceof DefaultInteger)
                return ((DefaultInteger)a).value();
        }
        return null;
    }

}

// Test Pojo
public class TestPojo extends DefaultPojo {
    @DefaultString("Hello world!")
    public String stringValue;
    @DefaultInteger(42);
    public int integerValue;
}

A continuación, los valores por defecto para un TestPojo se puede ajustar sólo con la ejecución test.setDetaults()

Otros consejos

Debe manualmente entrada del filtro a constructores y definidores. Bueno ... se puede utilizar la reflexión, pero yo no lo aconsejaría. Parte del trabajo de los constructores y definidores es la validación de entrada. Esto puede incluir cosas como:

public void setPrice(double price) {
  if (price < 0.0d) {
    throw new IllegalArgumentException("price cannot be negative " + price);
  }
  this.price = price;
}

y

public void setName(String name) {
  if (name == null) {
    throw new NullPointerException("name cannot be null");
  }
  this.name = name;
}

Se podría utilizar funciones de contenedor para la verificación real y lanzando la excepción.

Tal vez comprobar Hibernate Validator 4.0 , la implementación de referencia de la JSR 303: Bean Validation .

Este es un ejemplo de una clase anotada:

public class Address {

    @NotNull 
    private String line1;
    private String line2;
    private String zip;
    private String state;

    @Length(max = 20)
    @NotNull
    private String country;

    @Range(min = -2, max = 50, message = "Floor out of range")
    public int floor;

        ...
}

Para una introducción, ver Introducción a JSR 303 (Bean Validation) - parte 1 y parte 2 o la sección 'Introducción' de la guía de referencia que es parte de la distribución Hibernate Validator.

solución no reflectante para Java 8, sin necesidad de utilizar una serie de Si de, sería la de transmitir todos los campos y comprobar si hay nullness:

return Stream.of(id, name).allMatch(Objects::isNull);

Este sigue siendo bastante fácil de mantener, evitando el martillo reflexión. Esto devolverá cierto para los atributos nulos.

Se puede crear una función que devuelve un valor booleano y comprueba todos los atributos. Puede llamar a esa función para hacer el trabajo para usted.

Como alternativa, se puede inicializar el objeto con valores por defecto. De esa manera no hay necesidad para que usted pueda comprobar nada.

No tengo suficiente contexto para darle una respuesta correcta, pero voy a sugerir que haces código inmutable tanto como sea posible. Use campos public final. No más getters o setters: cada campo tiene que ser definido por el constructor. Su código es más corto, más fácil de leer y no le permite escribir código con efectos secundarios.

Esto no le impide el paso de argumentos nulos a su constructor, aunque ... Todavía se puede comprobar cada argumento según lo sugerido por @cletus, pero lo que sugiere que tirar IllegalArgumentException en lugar de NullPointerException que no hay dar nueva pista sobre lo que has hecho.

De todos modos, eso es lo que hago tanto como puedo y que mejoró mi código (legibilidad, la estabilidad) a una gran ampliación. Todo el mundo en mi equipo lo hace y estamos muy contentos con eso. Hemos aprendido que cuando tratamos de escribir código erlang donde todo es inmutable.

Espero que esto ayude.

He intentado esto y funciona sin ningún problema para validar si el campo está vacío. He respondido a su pregunta en parte ya que no he probado personalmente para agregar valores por defecto para los atributos

if(field.getText()!= null && !field.getText().isEmpty())

Espero que ayuda

Esto no es para comprobar null, en lugar Esto será útil en la conversión de un objeto existente a un objeto vacío (objeto fresco). No sé si esto es relevante o no, pero tenía tal requisito.

@SuppressWarnings({ "unchecked" })
static void emptyObject(Object obj) 
{
    Class c1 = obj.getClass();
    Field[] fields = c1.getDeclaredFields();

    for(Field field : fields)
    {
        try
        {
            if(field.getType().getCanonicalName() == "boolean")
            {
                field.set(obj, false);
            }
            else if(field.getType().getCanonicalName() == "char")
            {
                field.set(obj, '\u0000');
            }
            else if((field.getType().isPrimitive()))
            {
                field.set(obj, 0);
            }
            else
            {
                field.set(obj, null);
            }
        }
        catch(Exception ex)
        {

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