Можно ли в Java проверить, являются ли поля объектов пустыми, а затем добавить значение по умолчанию для всех этих атрибутов? - PullRequest
25 голосов
/ 27 января 2010

Мне нужно убедиться, что ни один атрибут объекта не равен нулю, и добавить значение по умолчанию на случай, если оно равно нулю. Есть ли простой способ сделать это, или я должен сделать это вручную, проверяя каждый атрибут по его получателям и установщикам?

Ответы [ 8 ]

38 голосов
/ 27 января 2010

Вы можете использовать отражение, чтобы перебрать поле объекта и установить их. Очевидно, вам понадобится какое-то отображение между типами или даже именами полей и требуемыми значениями по умолчанию, но это можно сделать довольно просто в цикле. Например:

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

[Update]

В современной Java вы можете использовать аннотации для установки значений по умолчанию для полей для каждого класса. Полная реализация может выглядеть так:

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

Тогда значения по умолчанию для TestPojo можно установить, просто набрав test.setDetaults()

9 голосов
/ 27 января 2010

Вам нужно вручную фильтровать ввод для конструкторов и сеттеров. Ну ... ты мог бы использовать отражение, но я бы не советовал. Часть работы конструкторов и сеттеров заключается в проверке ввода. Это может включать в себя такие вещи, как:

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

и

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

Вы можете использовать функции-обертки для фактической проверки и выдачи исключения.

6 голосов
/ 27 января 2010

Может быть проверено Hibernate Validator 4.0 , эталонная реализация JSR 303: Bean Validation .

Это пример аннотированного класса:

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;

        ...
}

Введение см. В Начало работы с JSR 303 (Bean Validation) - часть 1 и часть 2 или в разделе «Начало работы» справочного руководства, которое является частью дистрибутив Hibernate Validator.

3 голосов
/ 03 апреля 2017

Неотражающее решение для Java 8, без использования серии if, было бы для потоковой передачи всех полей и проверки на нулевое значение:

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

Это остается довольно легко поддерживать, избегая молотка отражения. Это вернет true для нулевых атрибутов.

0 голосов
/ 10 июня 2016

Это не проверка на нулевое значение, но это будет полезно при преобразовании существующего объекта в пустой объект (свежий объект). Я не знаю, имеет ли это отношение или нет, но у меня было такое требование.

@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)
        {

        }
    }
}
0 голосов
/ 01 марта 2014

Я попробовал это, и это работает без каких-либо проблем, чтобы проверить, если поле пустое. Я частично ответил на ваш вопрос, так как лично не пытался добавить значения по умолчанию к атрибутам

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

Надеюсь, это поможет

0 голосов
/ 27 января 2010

У меня недостаточно контекста, чтобы дать вам правильный ответ, но я предлагаю вам сделать код неизменным как можно больше. Используйте public final поля. Не более getters или setters: каждое поле должно быть определено constructor. Ваш код короче, более читабелен и не позволяет писать код с побочными эффектами.

Это не мешает вам передавать пустые аргументы в ваш конструктор, хотя ... Вы все равно можете проверить каждый аргумент, как предложено @cletus, но я предлагаю вам бросить IllegalArgumentException вместо NullPointerException, который не не дают никаких новых подсказок о том, что вы сделали.

Во всяком случае, это то, что я делаю столько, сколько могу, и это значительно улучшило мой код (читабельность, стабильность). Все в моей команде делают это, и мы очень довольны этим. Мы узнали, что, когда мы пытаемся написать некоторый код erlang, где все неизменно.

Надеюсь, это поможет.

0 голосов
/ 27 января 2010

Вы можете создать функцию, которая возвращает логическое значение и проверяет каждый атрибут. Вы можете вызвать эту функцию, чтобы выполнить работу за вас.

Кроме того, вы можете инициализировать объект значениями по умолчанию. Таким образом, вам не нужно выполнять какую-либо проверку.

...