Как пропустить проверку bean, если все поля для объекта пусты?

У меня есть объект-адрес вроде этого:

@Entity
public class Address implements java.io.Serializable {
    @Id @GeneratedValue(strategy = IDENTITY)
    private Long id;

    @Size(max = 100)
    private String street;

    @Size(max = 15)
    private String nr;

    @Field
    @Size(min = 1, max = 20) @NotBlank
    private String city;
}

Это часть нескольких других объектов. Для одного такого объекта адрес является необязательным. У меня есть представление, где наши пользователи могут редактировать весь объект через несколько входных форматов, включая несколько полей адреса.

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

Теперь проблема заключается в следующем: я не хочу сохранять объект Address в сущности, когда все поля адреса пустые. Для этого мне нужно пропустить проверку для объекта, если (и только если) все поля Address пусты. Как мне сделать это самым элегантным способом?

То, что я сейчас делаю, это пропустить проверку bean с помощью <o:validateBean disabled="true" /> для кнопки отправки, установив адрес null, если он выйдет пустым. Но это звучит как полный взлом, поскольку он отключает все проверки во всех случаях. Как я могу сделать лучше?

Ответ 1

Вы можете просто использовать EL в disabled атрибуте <f:validateBean><o:validateBean>). Вы можете использовать EL, чтобы проверить, было ли заполнено какое-либо из этих полей. Вы можете использовать атрибут binding для ссылки на компонент в EL. Вы можете проверить, было ли поле заполнено, проверяя значение параметра запроса, связанного с идентификатором клиента компонента.

Затем, чтобы отключить проверку bean в тех полях, когда #{addressIsEmpty} оценивает true, проще использовать <f:validateBean> вместо <o:validateBean>, поскольку первая может использоваться для обертывания нескольких входных компонентов.

Итак, все со всеми, это должно сделать:

<c:set var="addressIsEmpty" value="#{empty param[street.clientId] and empty param[nr.clientId] and empty param[city.clientId]}" />

<f:validateBean disabled="#{addressIsEmpty}">
    <h:inputText binding="#{street}" value="#{bean.address.street}" />
    <h:inputText binding="#{nr}" value="#{bean.address.nr}" />
    <h:inputText binding="#{city}" value="#{bean.address.city}" />
</f:validateBean>

<o:validateBean> проще использовать, если вы намерены управлять им на основе ввода или каждой команды.

Ответ 2

Перекрестная проверка нескольких полей может быть сложной проблемой. Но в этой ситуации сама по себе не проверка, которая вас беспокоит, а скорее возможность свести на нет какой-либо экземпляр в каком-то состоянии вашего bean до того, как вы сохраните объект.

Самый простой способ - пометить все поля, связанные с Address сущностью, как required="false" в вашем представлении, чтобы не заботиться о заполняемых полях (или просто опустить его как значение по умолчанию) и выполнить все проверки, а также модификации заполнителя в вашем действии, прямо перед вызовом службы EJB. Например:

public String save() {
    //do some checks
    if((entity.getAddress().getStreet() == null) && ...) {
        //assign address to null
        entity.setAddress(null);
    }
    entityService.persist(entity);
    return "success";
}