2

Sorry it's maybe an easy question but I can't find anything on Google. I'm parsing csvData with e.g. more than 100000 rows / objects. I want to check that ALL values for the attributes are valid before they get written into the database. Annotations like @Size or @Length do not help...

To give you an example:

Entity:

@Entity
@Data
public class Transaction {

    @Size(max = 30)
    private String timestamp;
}

The csv is parsed and the objects are written down in a List.

   List<Transaction> transaction = new ArrayList<>();
      // list will be filled
   try {
      databaseConnector.saveAllTransactions(transaction, transactionRepository);
   } catch (ConstraintViolationException exc) {
      System.out.println(exc.getMessage());
   }

The error that appears after the 5th object.

Hibernate: insert into transaction (amount, customer_customer_id, discount, receipt_no, receipt_pos_no, timestamp, unit_price) values (?, ?, ?, ?, ?, ?, ?)
Hibernate: insert into transaction (amount, customer_customer_id, discount, receipt_no, receipt_pos_no, timestamp, unit_price) values (?, ?, ?, ?, ?, ?, ?)
Hibernate: insert into transaction (amount, customer_customer_id, discount, receipt_no, receipt_pos_no, timestamp, unit_price) values (?, ?, ?, ?, ?, ?, ?)
Hibernate: insert into transaction (amount, customer_customer_id, discount, receipt_no, receipt_pos_no, timestamp, unit_price) values (?, ?, ?, ?, ?, ?, ?)
Hibernate: insert into transaction (amount, customer_customer_id, discount, receipt_no, receipt_pos_no, timestamp, unit_price) values (?, ?, ?, ?, ?, ?, ?)
Validation failed for classes [com.stuff.project.entity.Transaction] during persist time for groups [javax.validation.groups.Default, ]
List of constraint violations:[
    ConstraintViolationImpl{interpolatedMessage='muss zwischen 0 und 30 liegen', propertyPath=timestamp, rootBeanClass=class com.stuff.project.entity.Transaction, messageTemplate='{javax.validation.constraints.Size.message}'}
]

Only that you know how the method looks like.

public boolean saveAllTransactions(List<Transaction> transactions, TransactionRepository transactionRepository) {
    transactionRepository.saveAll(transactions);
    return true;
}

The only thing I could imagine is to go through the whole list of objects and check for each object the attributes for it's length like:

transactions.forEach(e -> e.getTimestamp().length != 30); ....

That does not seem to be very performance friendly...

CptDayDreamer
  • 1,526
  • 6
  • 25
  • 61

1 Answers1

2

First of all: performance shouldn't be your primary concern. You have a list with N entries, and when you want to check the string length for each of the N entries, hey: you have to iterate the N entries, and look at each one. Of course, you could theoretically do that in parallel, which, given "enough" data to work with, makes things quicker, at the cost of more CPU power being used.

The real problem: you start to implement "extra validation", instead of relying on your annotations. In other words: you are working "around" your framework. That is rarely a good idea.

Assuming we are talking generic Java (bean) annotations, the canonical answer would be to do two things:

  • to create a class that represents a list of your Transaction objects
  • to provide a custom validator that works on that list (and that knows to iterate all entries, and check that string length)
GhostCat
  • 137,827
  • 25
  • 176
  • 248
  • Imagine I have now 10 entities. Let's say each of this entities has 5 attributes and all are length restricted. Would that mean I need like run the method 50 times? Or let's at least say for a list of 100000 elements it runs for this 5 attributes 500000 times? What do you mean with a class that represents a list of your Transaction objects? – CptDayDreamer Jan 09 '20 at 13:17
  • @CptDayDreamer Again: when you have N objects, and each has M attributes you need to check, your code needs to look at N x M things. WIth list I mean: you define a bean (entity) class that holds a list of Transaction objects, and then you can **annotate** that list field and point to custom validation. – GhostCat Jan 09 '20 at 13:19
  • Sorry if I ask that things but you mean write my own annotation? So instead or complementary to @Size? Will it be check while writing objects? – CptDayDreamer Jan 09 '20 at 13:47
  • @CptDayDreamer The point is that you currently have annotations on the individual objects. Object A doesnt know or care about object B. Therefore each object gets validated in isolation, just before that object is written. Thus: you need somehow to express that you have a list of objects, that "belong" together. And one way to do that: create a custom annotation. See https://docs.jboss.org/hibernate/validator/5.0/reference/en-US/html/validator-customconstraints.html#validator-customconstraints-constraintannotation for example. – GhostCat Jan 09 '20 at 13:56
  • Ok I'm trying now. It looks like this: @Override public boolean isValid(List> value, ConstraintValidatorContext context) { ... But like this I can't access the attributes. And what is the best way to set or get the values for the length I want to set? I'm trying now but I just find very simple examples – CptDayDreamer Jan 09 '20 at 14:39
  • So any idea on my problem here: https://stackoverflow.com/questions/59668543/spring-boot-java-implementation-of-customannotation I've tried to do what you said but there is a problem – CptDayDreamer Jan 10 '20 at 09:47
  • @CptDayDreamer I will have a look, but I can't promise you much help. This is a bit out of my daily experience ... – GhostCat Jan 10 '20 at 12:38