0

I've decided to use Value Objects instead of String fields in my entity and I don't know how (and if it's even possible) to validate them using JPA Annotations like @Size, @Pattern and so on. Here is my Book entity:

   @Entity
@Access(AccessType.FIELD) // so I can avoid using setters for fields that won't change
public class Book {

  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  private Long bookId;

  @Embedded
  private Isbn isbn;
  @Embedded
  private Title title;
  @Embedded
  private Author author;
  @Embedded
  private Genre genre;
  @Embedded
  private PublicationYear publicationYear;
  private BigDecimal price;

  // jpa requirement
  public Book() {
  }

  public Book(Isbn isbn, Title title, Author author, Genre genre, PublicationYear publicationYear,
      BigDecimal price) {
    this.isbn = isbn;
    this.title = title;
    this.author = author;
    this.genre = genre;
    this.publicationYear = publicationYear;
    this.price = price;
  }

  public Long getBookId() {
    return bookId;
  }

  public Isbn getIsbn() {
    return isbn;
  }

  public Title getTitle() {
    return title;
  }

  public Author getAuthor() {
    return author;
  }

  public Genre getGenre() {
    return genre;
  }

  public BigDecimal getPrice() {
    return price;
  }

  public PublicationYear getPublicationYear() {
    return publicationYear;
  }

  // setter for price is needed because price of the book can change (discounts and so on)
  public void setPrice(BigDecimal price) {
    this.price = price;
  }

}

And here is my example value object - all are just using Strings.

   public class Isbn {
  private String isbn;

  // jpa requirement
  public Isbn() {
  }

  public Isbn(String isbn) {
    this.isbn = isbn;
  }

  public String getIsbn() {
    return isbn;
  }

  @Override
  public boolean equals(Object o) {
    if (this == o) {
      return true;
    }
    if (o == null || getClass() != o.getClass()) {
      return false;
    }

    Isbn isbn1 = (Isbn) o;

    return isbn != null ? isbn.equals(isbn1.isbn) : isbn1.isbn == null;
  }

  @Override
  public int hashCode() {
    return isbn != null ? isbn.hashCode() : 0;
  }

  @Override
  public String toString() {
    return "Isbn{" +
        "isbn='" + isbn + '\'' +
        '}';
  }
}

Is there a simple way to validate those objects? If it was a String in my entity instead of Isbn object I could just use @Pattern to match correct Isbn and be done with it.

EDIT1: Maybe there is a better way to validate value objects than above one? I'm kinda new to this stuff so would like to know if there is a better option to validate my entities.

17
  • They are each essentially String's right? Why do you need to create separate classes for each? Just use javax validation annotations; baeldung.com/javax-validation Commented Feb 27, 2017 at 22:57
  • Also I recommend using lombok for getter/setter/constructor generation; projectlombok.org Commented Feb 27, 2017 at 22:59
  • 1
    Well, that's exactly why you would use Value Objects: to swap your meaningless String to objects - have a read: martinfowler.com/bliki/ValueObject.html Commented Feb 27, 2017 at 23:00
  • Why would it be meaningless, what meaning are you adding by creating a hollow object? That is essentially wrapping the true String field Commented Feb 27, 2017 at 23:02
  • Have you read the article I just posted? It's explained there. And here is great speech about Value Objects and why you would use them: vimeo.com/13549100 I want to use them and am currently looking how to validate them - I could use just Strings but I think that using VOs is superior. Commented Feb 27, 2017 at 23:10

1 Answer 1

1

You can enforce validation of Object fields by utilizing @Valid annotation;

@Entity
@Access(AccessType.FIELD)
public class Book {

  @Embedded @Valid
  private Isbn isbn;
...
}

public class Isbn {
  @Pattern(//Pattern you'd like to enforce)
  private String isbn;
...
}

Then you can validate by yourself using the following;

ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
Validator validator = factory.getValidator();
Set<ConstraintViolation<User>> violations = validator.validate(book);
//if set is empty, validation is OK
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.