1

Why is Hibernate's validation - ConstraintViolationException - NOT thrown in main() of a SpringBoot app (SpringBoot's latest version) with spring-boot-starter-web:

@Validated
@SpringBootApplication
public class Application {
public static void main(String[] args) {
   SpringApplication.run(Application.class, args);
   someService.doStuff(new Item(null);  // WHY NOT THROWN????????!!!!!! 
   // Expecting ConstraintViolationException: doStuff.item.content: must not be null
}}
// ----------------------

public class Item {
    @NotNull
    String content;  // to be validated
   //constructor, getter, setter
}

@Validated
@Service
public class SomeService {
    void doStuff(@Valid Item item) {} // should break for Item's content = null
}

Strangely enough, in other cases Hibernate validation is working as expected for the same method call:

  1. ConstraintViolationException is thrown when I put the invalid call in a controller's contructor:
public SomeController(SomeService someService){
    this.someService = someService;
    someService.doStuff(new Item(null); // throws ConstraintViolationException  
}
  1. Also as expected, ConstraintViolationException is thrown when I put the invalid call in a constructor method and call the endpoint in a test or Postman
@GetMapping("item")
public String item() {
    someService.doStuff(new Item(null); // throws ConstraintViolationException
    return "You never get here.";
}
enhancedJack
  • 265
  • 1
  • 6
  • 15

1 Answers1

2

Not sure how are you getting someService instance in Application, but the following code works for me (every class in a different file):

@AllArgsConstructor
@Getter
@Setter
public class Item {

  @NotNull
  String content;
}



@Validated
@Service
public class SomeService {

  public void doStuff(@Valid Item item) {
    System.out.println(format("Item.content = %s", item.getContent()));
  }
}



@SpringBootApplication
public class TestingPurposeApplication {

  public static void main(String[] args) {
    ConfigurableApplicationContext context = SpringApplication.run(TestingPurposeApplication.class, args);
    SomeService someService = context.getBean(SomeService.class);
    someService.doStuff(new Item(null));
  }
}

The result:

ConstraintViolationException

Use:

ConfigurableApplicationContext context = SpringApplication.run(MyApplication.class, args);
MyClass myInstance = context.getBean(MyClass.class);

Is the suitable way to get a component managed by Spring in main method.

doctore
  • 3,855
  • 2
  • 29
  • 45
  • It does work! :-) I tried to get the bean like this: 1) static SomeService someService = new SomeService();. and also like this: 2)@Autowired static SomeService someService; // java.lang.NullPointerException. Why did 1) NOT start the Hibernate Violator? Why did 2) throw NLP?! – enhancedJack Aug 24 '20 at 07:25
  • 2
    Glad to help. Regarding to the ways you used to get `someService`, Spring hadn't started so 1) The static property is initialized before Spring runs. 2) Similar use case, but in this one, Spring won't "override" `@Autowired` property because your `public class Application` is not a Spring's component one, I mean, not a: `Service`, `Repository`, etc. For that reason, the way I told you is the best one in `main` method, because you will be sure about: Spring has run without problems and using returned `context`, Spring will provide you the required instance of the class you want. – doctore Aug 24 '20 at 08:45