PL-9470 BeanValidation annotation @RequiredView that will check if all view attributes are loaded for instance

This commit is contained in:
Yuriy Artamonov 2017-08-28 19:43:16 +04:00
parent 9b1bf38d79
commit a045a80030
6 changed files with 117 additions and 5 deletions

View File

@ -0,0 +1,45 @@
/*
* Copyright (c) 2008-2017 Haulmont.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.haulmont.cuba.core.global.validation;
import javax.validation.Constraint;
import javax.validation.Payload;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
/**
* Annotation that can be added to service method definitions to ensure that entity instances are loaded with all the
* attributes specified in the view.
*/
@Target({FIELD, METHOD, PARAMETER, ANNOTATION_TYPE, TYPE})
@Retention(RUNTIME)
@Constraint(validatedBy = RequiredViewValidator.class)
public @interface RequiredView {
String message() default "{msg://com.haulmont.cuba.core.global.validation/RequiredViewValidator.message}";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
/**
* @return name of the required view
*/
String value();
}

View File

@ -0,0 +1,57 @@
/*
* Copyright (c) 2008-2017 Haulmont.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.haulmont.cuba.core.global.validation;
import com.haulmont.cuba.core.entity.Entity;
import com.haulmont.cuba.core.global.PersistenceHelper;
import org.slf4j.LoggerFactory;
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import java.util.Collection;
public class RequiredViewValidator implements ConstraintValidator<RequiredView, Object> {
private String view;
@Override
public void initialize(RequiredView annotation) {
this.view = annotation.value();
}
@Override
public boolean isValid(Object value, ConstraintValidatorContext context) {
try {
if (value instanceof Entity) {
PersistenceHelper.checkLoadedView((Entity) value, view);
} else if (value instanceof Collection) {
@SuppressWarnings("unchecked")
Collection<Entity> entities = (Collection<Entity>) value;
for (Entity entity : entities) {
PersistenceHelper.checkLoadedView(entity, view);
}
}
return true;
} catch (IllegalArgumentException e) {
LoggerFactory.getLogger(RequiredViewValidator.class)
.debug("Failed validation of instance with required view: {}", e.getMessage());
return false;
}
}
}

View File

@ -42,4 +42,6 @@ org.hibernate.validator.constraints.ParametersScriptAssert.message = script expr
org.hibernate.validator.constraints.Range.message = must be between {min} and {max}
org.hibernate.validator.constraints.SafeHtml.message = may have unsafe html content
org.hibernate.validator.constraints.ScriptAssert.message = script expression "{script}" didn't evaluate to true
org.hibernate.validator.constraints.URL.message = must be a valid URL
org.hibernate.validator.constraints.URL.message = must be a valid URL
RequiredViewValidator.message = entity does not conform to required view {value}

View File

@ -42,4 +42,6 @@ org.hibernate.validator.constraints.NotBlank.message = не может быть
org.hibernate.validator.constraints.Length.message = длина должна быть между {min} и {max}
org.hibernate.validator.constraints.Email.message = email определен в неверном формате
org.hibernate.validator.constraints.EAN.message = неправильный штрихкод {type}
org.hibernate.validator.constraints.LuhnCheck.message = Контрольная цифра для ${validatedValue} неверна, проверка по алгоритму Луна завершена с ошибкой
org.hibernate.validator.constraints.LuhnCheck.message = Контрольная цифра для ${validatedValue} неверна, проверка по алгоритму Луна завершена с ошибкой
RequiredViewValidator.message = сущность не соответствует требуемому представлению {value}

View File

@ -49,6 +49,9 @@ public class BeanValidationImpl implements BeanValidation {
@Inject
protected UserSessionSource userSessionSource;
@Inject
protected EntityStates entityStates;
protected ConcurrentHashMap<Locale, ValidatorFactory> validatorFactoriesCache = new ConcurrentHashMap<>();
@Override
@ -113,7 +116,7 @@ public class BeanValidationImpl implements BeanValidation {
HibernateValidatorConfiguration configuration = Validation.byProvider(HibernateValidator.class)
.configure()
.timeProvider(new CubaValidationTimeProvider(timeSource))
.traversableResolver(new CubaValidationTraversableResolver(metadata))
.traversableResolver(new CubaValidationTraversableResolver(metadata, entityStates))
.messageInterpolator(new CubaValidationMessagesInterpolator(messages, locale));
return configuration;

View File

@ -16,6 +16,7 @@
package com.haulmont.cuba.core.sys.validation;
import com.haulmont.cuba.core.global.EntityStates;
import com.haulmont.cuba.core.global.Metadata;
import com.haulmont.cuba.core.global.PersistenceHelper;
import org.hibernate.validator.internal.engine.resolver.DefaultTraversableResolver;
@ -30,9 +31,11 @@ public class CubaValidationTraversableResolver extends DefaultTraversableResolve
private final Logger log = LoggerFactory.getLogger(CubaValidationTraversableResolver.class);
protected Metadata metadata;
protected EntityStates entityStates;
public CubaValidationTraversableResolver(Metadata metadata) {
public CubaValidationTraversableResolver(Metadata metadata, EntityStates entityStates) {
this.metadata = metadata;
this.entityStates = entityStates;
}
@Override
@ -48,6 +51,6 @@ public class CubaValidationTraversableResolver extends DefaultTraversableResolve
return true;
}
return PersistenceHelper.isLoaded(traversableObject, traversableProperty.getName());
return entityStates.isLoaded(traversableObject, traversableProperty.getName());
}
}