Возможно ли в Java проверить, являются ли поля объектов нулевыми, а затем добавить значение по умолчанию ко всем этим атрибутам?

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

  •  23-09-2019
  •  | 
  •  

Вопрос

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

Это было полезно?

Решение

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

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

[Обновление]

В современной 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()

Другие советы

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

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

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

Может быть, проверить Валидатор гибернации 4.0, эталонная реализация JSR 303:Валидация компонента.

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

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 (проверка компонентов) – часть 1 и часть 2 или раздел "Начало работы" справочного руководства, которое является частью дистрибутива Hibernate Validator.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

        }
    }
}
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top