Announcement Announcement Module
Collapse
No announcement yet.
Autowiring does not work inside custom constraint validator using Spring-Test-MVC Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Autowiring does not work inside custom constraint validator using Spring-Test-MVC

    Dear Spring Community,

    I have an issue with autowiring inside a custom constraint validator when running an integration test using spring-test-mvc. The service I require is null.

    However when I run the web app, its is auotwired correctly.

    Custom Constraint Validator (Booking Service is null!)

    Code:
    public class CheckAvailabilityValidator implements ConstraintValidator<CheckAvailability, Booking> {
    
    	private DateTimeFormatter formatter;
    	private int maxNumberOfBookings = 2;
    	
    	@Autowired
    	private BookingService bookingService;
    
    	public void initialize(CheckAvailability constraintAnnotation) {
    		formatter = DateTimeFormat.forPattern("dd/MM/yyyy");
    	}
    
    	public boolean isValid(Booking booking, ConstraintValidatorContext constraintContext) {
    		
    		if (booking.getArrivalDate() == null || booking.getDepartureDate() == null) {
    			return false;
    		}
    
    		DateTime arrivalDate = formatter.parseDateTime(booking.getArrivalDate());
    		DateTime departureDate = formatter.parseDateTime(booking.getDepartureDate());
    		
    		if (bookingService.findBookingsByDateRange(arrivalDate,departureDate).size() > maxNumberOfBookings) {
    			return false;
    		} else {
    			return true;
    		}
    	}
    
    }
    Annotation
    Code:
    @Target({ TYPE, ANNOTATION_TYPE })
    @Retention(RUNTIME)
    @Constraint(validatedBy = CheckAvailabilityValidator.class)
    @Documented
    public @interface CheckAvailability {
    
        String message() default "{we.do.not.have.availability}";
        
        Class<?>[] groups() default {};
    
        Class<? extends Payload>[] payload() default {};
    
    }
    Service
    Code:
    @Service
    public class BookingService implements IBookingService{
    	
            @Autowired
            private BookingDao bookingDao;
    	
    	private static Logger logger = LoggerFactory.getLogger(BookingService.class);
    	
    	@Override
    	public List<Booking> findBookingsByDateRange(DateTime from, DateTime to) {
    		return bookingDao.findBookingsByDateRange(from, to);
                   
    	}
    	
    }
    Unit Test

    Code:
    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration(classes = {BookingControllerConfig.class})
    public class BookingControllerTest {
    
            @Autowired
    	private BookingController bookingController;
    	
    	private List<Booking> bookingList = new ArrayList<Booking>();
    
            .....
    	
            @Test
    	public void testPostBookingDetails() throws Exception {
    
    
    		
             standaloneSetup(bookingController).build().perform(post("/booking_details")
    				.param("arrivalDate", "01/01/2013")
    				.param("departureDate", "09/01/2013")
    				.param("accomendationType", "Suite")
    				.param("numberOfAdults", "2")
    				.param("numberOfChildren", "2"))		
    			.andDo(print())
    			.andExpect(status().isOk());
    	}
    ...
    
    }
    Config

    Code:
    @Configuration
    public class BookingControllerConfig {
    	
    	@Bean
    	public BookingController bookingController() {
    		return new BookingController();
    	}
    	
    	@Bean
    	public BookingService bookingService() {
    		return Mockito.mock(BookingService.class);
    	}
    
    .....
    
    }
    Controller
    Code:
    @Controller
    public class BookingController {
    
       ...
    
          @RequestMapping(value = "/booking_details", method = RequestMethod.POST)
          public ModelAndView showBookingDetails(@Validated Booking booking, BindingResult bindingResult, ContactDetails  
                                                                   contactDetails, HttpServletResponse response) throws IOException {
          ...
          }
      ...
    }
    Any ideas?
    Last edited by DJC_Spring; Jan 8th, 2013, 07:41 AM.

  • #2
    Hi Everyone,

    With Thanks to Rossen Stoyanchev I have this working.

    In short the problem is to do with standloneSetup with does not load spring configuration.

    One option is to create a LocalValidatorFactoryBean configured with a SpringConstraintValidatorFactory and plug it into the standaloneSetup builder.

    However I decided to migrate from spring-test-mvc to spring-test in 3.2.

    All that was required was to annotate my test class with @WebAppConfiguration, load in my spring configuration files with @ContextConfiguration and then @Autowired WebApplicationContext

    Example

    Code:
    @RunWith(SpringJUnit4ClassRunner.class)
    @WebAppConfiguration
    @ContextConfiguration(value ={
    		"file:src/main/webapp/WEB-INF/spring/appServlet/servlet-context.xml",
    		"classpath:/META-INF/config/service-context.xml ",
    		"classpath:/META-INF/config/persistence-context.xml",
    		"classpath:/META-INF/config/dataSource-context.xml"
    })
    
    public class BookingControllerAvailabilityTestRefactor {
    	
    	@Autowired
    	private BookingController bookingController;
    	private String arrivalDate;
    	private String departureDate;
    	private static String dateFormat = "dd/MM/yyyy";
    	
    	@Autowired
    	private WebApplicationContext wac;
    	private MockMvc mvc;
    	
    	@Before
    	public void setup() {
    		arrivalDate= DateTime.now().plusDays(1).toString(dateFormat);
    		departureDate= DateTime.now().plusDays(5).toString(dateFormat);
    		this.mvc = webAppContextSetup(this.wac).build();
    	}
    	
    	@Test
    	public void testPostBookingDetails() throws Exception {
    	    this.mvc.perform(post("/booking_details")
    	    		.param("arrivalDate", this.arrivalDate)
    				.param("departureDate", this.departureDate)
    				.param("accomendationType", "Suite")
    				.param("numberOfAdults", "2")
    				.param("numberOfChildren", "2"))
    			.andDo(print())
    			.andExpect(status().isOk());
    	        
    	  }
    	
    		
    }
    I can now @Autowire services in my custom jsr annotation validator.

    Hope this helps others

    Regards
    Darren C.

    Comment

    Working...
    X