É possível em Java verificar se os campos de objetos são nulos e, em seguida, adicionar valor padrão a todos esses atributos?

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

  •  23-09-2019
  •  | 
  •  

Pergunta

Preciso garantir que nenhum atributo de objeto seja nulo e adicione valor padrão caso seja nulo. Existe alguma maneira fácil de fazer isso, ou eu tenho que fazê -lo manualmente verificando todos os atributos por seus getters e setters?

Foi útil?

Solução

Você pode usar a reflexão para iterar sobre o campo do objeto e defini -los. Obviamente, você precisaria de algum tipo de mapeamento entre tipos ou mesmo nomes de campo e valores padrão necessários, mas isso pode ser feito com bastante facilidade em um loop. Por exemplo:

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

Atualizar

Com o Java moderno, você pode usar anotações para definir os valores padrão para os campos por classe. Uma implementação completa pode ser assim:

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

Em seguida, valores padrão para um TestPojo pode ser definido apenas correndo test.setDetaults()

Outras dicas

Você precisa filtrar manualmente a entrada para construtores e setters. Bem ... você poderia usar a reflexão, mas eu não o aconselho. Parte do trabalho de construtores e setters é validar a entrada. Isso pode incluir coisas como:

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

e

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

Você pode usar funções de wrapper para a verificação real e lançar a exceção.

Talvez verifique Hibernate Validator 4.0, a implementação de referência do JSR 303: Validação de feijão.

Este é um exemplo de classe 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 uma introdução, veja Introdução ao JSR 303 (Validação do Bean) - Parte 1 e parte 2 ou a seção "Introdução" do Guia de Referência, que faz parte da distribuição do Validador Hibernato.

Solução não reflexiva para o Java 8, sem usar uma série de IF, seria transmitir todos os campos e verificar a nula:

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

Isso permanece bastante fácil de manter, evitando o martelo de reflexão. Isso retornará verdadeiro para atributos nulos.

Você pode criar uma função que retorne um valor booleano e verifique todos os atributos. Você pode chamar essa função para fazer o trabalho para você.

Como alternativa, você pode inicializar o objeto com valores padrão. Dessa forma, não há necessidade de você fazer uma verificação.

Não tenho contexto suficiente para lhe dar uma resposta correta, mas vou sugerir que você faça seu código imutável tanto quanto possível. Usar public final Campos. Não mais getters ou setters : Todo campo deve ser definido pelo constructor. Seu código é mais curto, mais legível e impede que você escreva código com efeitos colaterais.

Isso não impede que você passe argumentos nulos para o seu construtor ... você ainda pode verificar todos os argumentos, conforme sugerido por @cletus, mas vou sugerir que você jogue IllegalArgumentException ao invés de NullPointerException Isso não dá nenhuma nova dica sobre o que você fez.

De qualquer forma, é o que eu faço o máximo que posso e melhorou meu código (legibilidade, estabilidade) em grande parte. Todos na minha equipe fazem isso e estamos muito felizes com isso. Aprendemos que quando tentamos escrever alguns erlang código onde tudo é imutável.

Espero que isto ajude.

Eu tentei isso e funciona sem problemas para validar se o campo estiver vazio. Eu respondi sua pergunta parcialmente, pois não tentei pessoalmente adicionar valores padrão aos atributos

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

Espero que ajude

Isso não deve verificar se há NULL; em vez disso, será útil para converter um objeto existente em um objeto vazio (objeto fresco). Não sei se isso é relevante ou não, mas eu tinha esse 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 em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top