javahibernatejpajakarta-validation

Validation doesn't work on Hibernate Entity's fields


I'm working on a project using JavaFX, Hibernate.

I added constraints of not being empty to a String primary key but it doesn't perform any validation as I expected. It still accept an empty string as a valid input.

I tried @NotEmpty, @NotBlank, @Size, @Pattern but it doesn't work. When I pass a null object to @NotNull, it still does the job. I'm new to Hibernate and anything related to it so I guess I'm missing basic knowledge.

I also tried to search for making validation on Hibernate but I found solutions about Spring MVC, and some ways of making validation which I tried above. I find that Hibernate Validator contains many deprecated annotations and I'm using Jakarta Validation, I don't know if it related to this.

Update: I tried to set hibernate.hbmddl.auto to create-drop to recreate tables while I'm modifying constraints but it doesn't work.

Here is my code. I want the Apartment.id to be non-empty since every resident should live in an apartment.

Apartment.java

package com.example.demo;

import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import jakarta.validation.constraints.NotBlank;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@Entity
@NoArgsConstructor
@AllArgsConstructor
public class Apartment {
    @Id
    @NotBlank
    private String id;
}

Resident.java

package com.example.demo;

import jakarta.persistence.*;
import jakarta.validation.constraints.NotBlank;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@Entity
@AllArgsConstructor
@NoArgsConstructor
public class Resident {
    @Id
    @GeneratedValue
    private Integer id;

    private String firstName;

    private String lastName;

    public Resident(String firstName, String lastName, Apartment apartment) {
        this.firstName = firstName;
        this.lastName = lastName;
        this.apartment = apartment;
    }

    @ManyToOne
    @JoinColumn(nullable = false)
    private Apartment apartment;

}

Code that using two entities

package com.example.demo;

import javafx.fxml.FXML;
import javafx.scene.control.Button;
import javafx.scene.control.TextField;

public class ResidentFormController {

    public TextField firstNameTextField;
    public TextField lastNameTextField;
    public TextField apartmentTextField;
    public Button submitButton;

    private ResidentService residentService;
    private ApartmentService apartmentService;

    @FXML
    public void initialize() {
        residentService = new ResidentService(new ResidentRepository());
        apartmentService = new ApartmentService(new ApartmentRepository());
    }

    public void submitButtonOnAction() {
        Apartment apartment = new Apartment(apartmentTextField.getText());
        apartmentService.merge(apartment);
        residentService.persist(new Resident(
                firstNameTextField.getText(),
                lastNameTextField.getText(),
                apartment
        ));
        SceneManager.switchScene(Scene.RESIDENT_LIST.getFileName());
    }
}

I found this question Validation doesn't work on EntityManager.merge()

and tried it as the following code, but still not working

public void merge(T entity) {
    HibernateUtility.getSessionFactory().inTransaction(session -> {
        session.merge(entity);
        session.flush();
    });
}

Here is the GitHub repository: https://github.com/GiaoLe/demo

If there is any part of the code is impractical, it's nice to have some instructions or reference since I find so many obsolete tutorials on Hibernate.

Thank you so much for your time.


Solution

  • I don't use Hibernate validations. I prefer much more to rely on the database. Please check how to create constraints on columns for your specific database. I think in your case is Mysql.

    For your code:

    OK first think why you want to set id on Apartment from textfield? I think it is better if you generated it. You can add in Apartment additional field number or something similar. It is just good practice your users not to edit ids from your records.

    Your Database is your source of data so it is the most important place to put constraints. You also can add constraint that the apartment number (the new column) should not be null in database. Then you will not save rows without ids and numbers.

    In your code I would first check if the text fields actually have values and then the rest:

    public class ResidentFormController {
    
    ...............
     
       public void submitButtonOnAction() {
    
          if (apartmentTextField.getText() == null || apartmentTextField.getText().trim().isEmpty()) {
              Integer apartmentNumber = apartmentTextField.getText()
              // 1. get the apartment from the db based on number
              Query<User> query = session.createQuery("from Apartment a where a.number=:number", Apartment.class);
              query.setParameter("number", apartmentNumber);
              Apartment apartment = query.uniqueResult()
    
             Apartment savedApartment;
             // 2.  If null save the apartment in DB before using it
              if(apartment == null)
              {
                 savedApartment = apartmentService.persist(new Apartment(apartmentNumber));
              }
              else
              {
                 savedApartment = apartment;
              }
              // 3. continue with your code
              residentService.persist(new Resident(
                   firstNameTextField.getText(),
                   lastNameTextField.getText(),
                   savedApartment
              ));
              SceneManager.switchScene(Scene.RESIDENT_LIST.getFileName());
              
          }
          else { 
                 // return some error message field is empty
          }
    
       }
    
    }
    

    Update

    Ok, I check this specification: https://docs.jboss.org/hibernate/stable/validator/reference/en-US/html_single/#validator-gettingstarted-createmodel

    According to it you need this dependency in your pom.xml:

    <dependency>
        <groupId>org.glassfish.expressly</groupId>
        <artifactId>expressly</artifactId>
        <version>5.0.0</version>
    </dependency>
    

    And also for the CDI:

    <dependency>
        <groupId>org.hibernate.validator</groupId>
        <artifactId>hibernate-validator-cdi</artifactId>
        <version>8.0.1.Final</version>
    </dependency>
    

    Can you please add it and check if the validation is working?