2012-10-01 9 views
9

Ho un problema con il trasferimento dei bean all'interno di un validatore di vincoli personalizzato. Un'istanza di validatore di vincoli non viene fornita utilizzando Spring's LocalValidatorFactoryBean. Il provider JSR-303 è hibernate-validator 4.2.0.Final. ConfigurazioneSpring 3.1 Autowiring non funziona all'interno del validatore di vincoli personalizzati

Primavera estratto:

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

personalizzato Vincolo Validator:

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

della nota:

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 è un altro @Service fagioli annotato che non dipende da someservice ...

Il problema è che ottengo un NPE come autowiring non funziona; qualcun altro sta gestendo le istanze del validatore personalizzato e non Spring ...

Grazie in anticipo per qualsiasi tipo di consiglio.

+0

Domanda Claudiu - Esistono due diversi contesti dell'applicazione: uno dichiarato tramite ContextLoaderListener e uno tramite DispatcherServlet, poiché @ è stato convalidato al livello dei metodi di servizio, probabilmente è necessario dichiarare anche LocalValidatorFactoryBean nel contesto dell'applicazione Web principale? –

+0

Beh, ho trovato alcune anomalie relative al numero di istanze LocalValidatorFactoryBean. La dichiarazione che ho dato nella descrizione "domanda" si trova in un servizio-content.xml => questa è un'istanza. C'è un'altra istanza creata automaticamente quando si utilizza => se si ha ragione sull'avere un'applicazione Web di root. –

+0

Dopo aver verificato che sia stata creata una sola istanza LocalValidatorFactoryBean, mi sono spostato per verificare anche quante istanze di ReadOnlyValidator sono state create. Utilizzando jmap -histo: live | grep "ReadOnlyValidator", ho notato che viene creata solo un'istanza, ma solo quando viene chiamato il metodo di servizio updateType per la prima volta e non quando viene inizializzato LocalValidatorFactBean.Penso che il motore di convalida in ibernazione crei semplicemente la propria istanza di validatore di vincoli. Come posso "forzare" LocalValidatorFactoryBean per gestire l'istanza ReadOnlyValidator in modo da poter utilizzare il cablaggio del bean? –

risposta

9

Trovato il problema. Lo stesso riferimento fagiolo "validatore" deve essere utilizzato da MethodValidationPostProcessor e mvc: annotazione-driven dichiarazione:

servizio 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> 
    ... 

dispatcher-servlet.xml

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

Claudiu, significa che è necessario registrare ogni nuovo validatore con MethodValidationPostProcessor. Sai come implementarlo con una Java Config. Sto espirando lo stesso problema. L'unica differenza è che sto autowiring un'interfaccia e che sto usando Java Config e non xml. – Tito

+0

Ho dovuto "iniettare" il validatore in MethodValidationPostProcessor. –

+0

se bean LocalValidatorFactoryBean e MethodValidationPostProcessor sono definiti in dispatcher-servlet.xml, @Validated non funzionerà. – Bodil

4

Tito, per favore controlla se puoi usare qualcosa come sotto per la configurazione di 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; 
    } 

    ... 
} 

Per riutilizzare il bean di convalida in un bean di configurazione diverso, è possibile utilizzare l'annotazione @Import.

Problemi correlati