2012-10-01 51 views
9

Tengo un problema con el autoenvío de beans dentro de un validador de restricciones personalizado. No se proporciona una instancia de validador de restricción utilizando LocalValidatorFactoryBean de Spring. El proveedor JSR-303 es hibernate-validator 4.2.0.Final. configuraciónSpring 3.1 El autoenrutamiento no funciona dentro del validador de restricciones personalizado

primavera extracto:

<!-- JSR 303 validation --> 
<bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean" /> 
<bean class="org.springframework.validation.beanvalidation.MethodValidationPostProcessor"/> 

Custom Constraint Validador:

import javax.validation.ConstraintValidator; 
import javax.validation.ConstraintValidatorContext; 

import org.springframework.beans.factory.annotation.Autowired; 

import com.model.Subject; 
import com.services.SomeTypeService; 

public class ReadOnlyValidator implements ConstraintValidator<ReadOnly, String> { 

@Autowired 
private SomeTypeService someTypeService; 

@Override 
public void initialize(ReadOnly constraintAnnotation) { } 

@Override 
public boolean isValid(String type, ConstraintValidatorContext context) { 
    try { 
     if (null != type) { 
         return !someTypeService.isReadonly(type); 
        } 
    } catch (Exception e) { 
     e.printStackTrace(); 
    } 

    return false; 
} 
} 

Anotación:

import static java.lang.annotation.ElementType.*; 
import static java.lang.annotation.RetentionPolicy.*; 

import java.lang.annotation.Documented; 
import java.lang.annotation.Retention; 
import java.lang.annotation.Target; 

import javax.validation.Constraint; 
import javax.validation.Payload; 

@Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER }) 
@Retention(RUNTIME) 
@Constraint(validatedBy = ReadOnlyValidator.class) 
@Documented 
public @interface ReadOnly { 
String message() default "{constraints.subjecttype.readonly}"; 
public abstract Class<?>[] groups() default {}; 
public abstract Class<? extends Payload>[] payload() default {}; 
} 

SomeService:

@Validated 
public interface SomeService { 
    ... 
    public void updateType(@ReadOnly String type) throws SomeException; 
    ... 
} 

SomeServiceImpl:

@Service 
public class SomeServiceImpl implements SomeService { 
    ... 
    public void updateType(String type) throws SomeException { 
    // do something 
    } 
    ... 
} 

SomeTypeService es otro Bean anotado @Service que no depende de SomeService ...

El problema es que me sale un NPE como autowiring no funciona; alguien más está administrando las instancias personalizadas del validador y no Spring ...

Gracias de antemano por cualquier tipo de asesoramiento.

+0

Pregunta Claudiu: ¿Tiene dos contextos de aplicación diferentes, uno declarado a través de ContextLoaderListener y otro a través de DispatcherServlet, ya que se ha validado a nivel de métodos de servicio, probablemente también deba declarar LocalValidatorFactoryBean en el contexto de la aplicación web raíz? –

+0

Bueno, encontré algunas anomalías relacionadas con el número de instancias de LocalValidatorFactoryBean. La declaración que di en la descripción de la "pregunta" se encuentra en un servicio-contenido.xml => esta es una instancia. Hay otra instancia creada automáticamente al usar => usted tiene razón acerca de tener una aplicación web raíz. –

+0

Después de verificar que solo se creó una instancia de LocalValidatorFactoryBean, me he movido para verificar también cuántas instancias de ReadOnlyValidator se crearon. Usando jmap -histo: live | grep "ReadOnlyValidator", me he dado cuenta de que solo se crea una instancia, pero solo cuando se llama al método de servicio updateType por primera vez y no cuando se inicializa LocalValidatorFactBean.Creo que el motor de validación de hibernación simplemente crea su propia instancia de validación de restricciones. ¿Cómo podría "forzar" a LocalValidatorFactoryBean a administrar la instancia de ReadOnlyValidator para que se pueda usar el cableado de bean? –

Respuesta

9

Encontró el problema. El mismo "validador" referencia de bean debe ser utilizado por MethodValidationPostProcessor y MVC: anotación impulsada declaración:

servicio context.xml

<!-- JSR 303 validation --> 
<bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean"/> 
<bean class="org.springframework.validation.beanvalidation.MethodValidationPostProcessor"> 
    <property name="validator" ref="validator"/> 
</bean> 
    ... 

despachador-servlet.xml

... 
<mvc:annotation-driven validator="validator" /> 
... 
+0

Claudiu, ¿esto significa que tenemos que registrar cada nuevo validador con el MethodValidationPostProcessor? ¿Sabes cómo implementar esto con una configuración de Java? Estoy expirando el mismo problema. La única diferencia es que estoy autoinstalando una interfaz y que estoy usando Java Config y no xml. – Tito

+0

Tuve que "inyectar" el validador en el MethodValidationPostProcessor. –

+0

si bean LocalValidatorFactoryBean y MethodValidationPostProcessor definidos en dispatcher-servlet.xml el @Validated no funcionará. – Bodil

4

Tito, compruebe si puede utilizar algo como lo siguiente para la configuración de Java:

@Configuration 
public class SampleConfig { 
    ... 

    @Bean 
    public Validator validator() { 
    return new LocalValidatorFactoryBean().getValidator(); 
    } 

    @Bean 
    public MethodValidationPostProcessor mvpp() { 
    MethodValidationPostProcessor mvpp = new MethodValidationPostProcessor(); 
    mvpp.setValidator(validator()); 

    return mvpp; 
    } 

    ... 
} 

Para reutilizar el bean de validación en un bean de configuración diferente, puede usar la anotación @Import.

Cuestiones relacionadas