Given this bean:
@Data
public class Contact {
@PreAssignmentValidator(validator = MustMatchRegexExpression.class, paramString = "^[A-Za-z]{3,8}$")
@CsvBindByName(column = "Contact First Name", required = true)
private String contactFirstName;
@PreAssignmentValidator(validator = MustMatchRegexExpression.class, paramString = "^[0-9]{10}$")
@CsvBindByName(column = "Phone Number", required = true)
private String phone;
}
and the CsvToBeanBuilder() configured as follows:
...
final CsvToBean<Contact> beans = new CsvToBeanBuilder<Contact>(
Files.newBufferedReader(csvFilePath, StandardCharsets.UTF_8))
.withType(Contact.class)
.withThrowExceptions(false)
.build();
this.contacts = beans.parse();
beans.getCapturedExceptions().stream().forEach(ex -> System.out.println(ex.getMessage()));
...
If I give it a file like:
Contact First Name,Phone Number
joe1,1234567890
jane,123456789
I (correctly) get these error messages:
Field userName value "joe1" did not match expected format of ^[A-Za-z]{3,8}$
Field phone value "123456789" did not match expected format of ^[0-9]{10}$
Since I am passing these messages back to the user, I would prefer if the error message used the CSV column name instead of the bean's field name, and if I can provide a custom validation message -- maybe as an additional field the @PreAssignmentValidator? -- so that the messages look like:
Field 'User Name' value "joe1" did not match expected format of '3 - 8 alphabetic characters'
Field 'Phone Number' value "123456789" did not match expected format of '10 digits'
Any suggestions/pointers on how I can do this without writing some custom logic to transform these messages?
Thank you!
Code updated based on suggestion from @andrewjames
@Getter
public class Contact {
//@PreAssignmentValidator(validator = MustMatchRegexExpression.class, paramString = "^[A-Za-z]{3,8}$")
@CsvBindByName(column = "Contact First Name", required = true)
private String contactFirstName;
//@PreAssignmentValidator(validator = MustMatchRegexExpression.class, paramString = "^[0-9]{10}$")
@CsvBindByName(column = "Phone Number", required = true)
private String phone;
public void setContactFirstName(String contactFirstName) throws CsvValidationException {
if (contactFirstName.length() < 3 || contactFirstName.length() > 8) {
throw new CsvValidationException("'Contact First Name' must be between 3-8 characters long");
}
this.contactFirstName = contactFirstName;
}
public void setPhone(String phone) throws CsvValidationException {
if (phone.length() != 10) {
throw new CsvValidationException("'Phone Number' must be between 10 digits long");
}
this.phone = phone;
}
}
public class ContactTest {
private static final String HEADER = "Contact First Name,Phone Number\n";
@Test
public void test() throws Exception {
String data = HEADER
+ "jo,1234567890\n"
+ "al,123456789"; // This row should generate two exceptions
CsvToBean<Contact> csvToBean = new CsvToBeanBuilder<Contact>(new StringReader(data))
.withType(Contact.class)
.withThrowExceptions(false)
// .withExceptionHandler(new ExceptionHandlerQueue()) // Tried this way after commenting previous line
.build();
List<Contact> beans = csvToBean.parse();
csvToBean.getCapturedExceptions().stream().forEach((ex) -> {
System.out.println((int) ex.getLineNumber() + " -- " + ex.getMessage());
});
}
}
But now the csvToBean.parse() just throws the exeptions. And For the second row, I only get the first exception:
Exception in thread "pool-1-thread-2" java.lang.RuntimeException: com.opencsv.exceptions.CsvBeanIntrospectionException: An introspection error was thrown while attempting to manipulate property contactFirstName of bean org.lotia.example.entity.Contact.
at com.opencsv.bean.concurrent.ProcessCsvLine.run(ProcessCsvLine.java:111)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
at java.base/java.lang.Thread.run(Thread.java:834)
Caused by: com.opencsv.exceptions.CsvBeanIntrospectionException: An introspection error was thrown while attempting to manipulate property contactFirstName of bean org.lotia.example.entity.Contact.
at com.opencsv.bean.AbstractBeanField.assignValueToField(AbstractBeanField.java:290)
at com.opencsv.bean.AbstractBeanField.setFieldValue(AbstractBeanField.java:182)
at com.opencsv.bean.AbstractMappingStrategy.setFieldValue(AbstractMappingStrategy.java:607)
at com.opencsv.bean.AbstractMappingStrategy.populateNewBean(AbstractMappingStrategy.java:330)
at com.opencsv.bean.concurrent.ProcessCsvLine.processLine(ProcessCsvLine.java:131)
at com.opencsv.bean.concurrent.ProcessCsvLine.run(ProcessCsvLine.java:87)
... 3 more
Caused by: java.lang.reflect.InvocationTargetException
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:566)
at com.opencsv.bean.FieldAccess.lambda$determineAssignmentMethod$3(FieldAccess.java:79)
at com.opencsv.bean.FieldAccess.setField(FieldAccess.java:115)
at com.opencsv.bean.AbstractBeanField.assignValueToField(AbstractBeanField.java:286)
... 8 more
Caused by: com.opencsv.exceptions.CsvValidationException: 'Contact First Name' must be between 3-8 characters long
at org.lotia.example.entity.Contact.setContactFirstName(Contact.java:23)
... 15 more
Exception in thread "pool-1-thread-1" java.lang.RuntimeException: com.opencsv.exceptions.CsvBeanIntrospectionException: An introspection error was thrown while attempting to manipulate property contactFirstName of bean org.lotia.example.entity.Contact.
at com.opencsv.bean.concurrent.ProcessCsvLine.run(ProcessCsvLine.java:111)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
at java.base/java.lang.Thread.run(Thread.java:834)
Caused by: com.opencsv.exceptions.CsvBeanIntrospectionException: An introspection error was thrown while attempting to manipulate property contactFirstName of bean org.lotia.example.entity.Contact.
at com.opencsv.bean.AbstractBeanField.assignValueToField(AbstractBeanField.java:290)
at com.opencsv.bean.AbstractBeanField.setFieldValue(AbstractBeanField.java:182)
at com.opencsv.bean.AbstractMappingStrategy.setFieldValue(AbstractMappingStrategy.java:607)
at com.opencsv.bean.AbstractMappingStrategy.populateNewBean(AbstractMappingStrategy.java:330)
at com.opencsv.bean.concurrent.ProcessCsvLine.processLine(ProcessCsvLine.java:131)
at com.opencsv.bean.concurrent.ProcessCsvLine.run(ProcessCsvLine.java:87)
... 3 more
Caused by: java.lang.reflect.InvocationTargetException
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:566)
at com.opencsv.bean.FieldAccess.lambda$determineAssignmentMethod$3(FieldAccess.java:79)
at com.opencsv.bean.FieldAccess.setField(FieldAccess.java:115)
at com.opencsv.bean.AbstractBeanField.assignValueToField(AbstractBeanField.java:286)
... 8 more
Caused by: com.opencsv.exceptions.CsvValidationException: 'Contact First Name' must be between 3-8 characters long
at org.lotia.example.entity.Contact.setContactFirstName(Contact.java:23)
... 15 more
java.lang.RuntimeException: com.opencsv.exceptions.CsvBeanIntrospectionException: An introspection error was thrown while attempting to manipulate property contactFirstName of bean org.lotia.example.entity.Contact.
at com.opencsv.bean.concurrent.IntolerantThreadPoolExecutor.checkExceptions(IntolerantThreadPoolExecutor.java:253)
at com.opencsv.bean.concurrent.LineExecutor.checkExceptions(LineExecutor.java:67)
at com.opencsv.bean.concurrent.IntolerantThreadPoolExecutor.areMoreResultsAvailable(IntolerantThreadPoolExecutor.java:303)
at com.opencsv.bean.concurrent.IntolerantThreadPoolExecutor.tryAdvance(IntolerantThreadPoolExecutor.java:313)
at com.opencsv.bean.concurrent.LineExecutor.tryAdvance(LineExecutor.java:24)
at java.base/java.util.Spliterator.forEachRemaining(Spliterator.java:326)
at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:484)
at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:474)
at java.base/java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:913)
at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
at java.base/java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:578)
at com.opencsv.bean.CsvToBean.parse(CsvToBean.java:117)
at org.lotia.example.ContactTest.test(ContactTest.java:28)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:566)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:69)
at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:33)
at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:220)
at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:53)
Caused by: com.opencsv.exceptions.CsvBeanIntrospectionException: An introspection error was thrown while attempting to manipulate property contactFirstName of bean org.lotia.example.entity.Contact.
at com.opencsv.bean.AbstractBeanField.assignValueToField(AbstractBeanField.java:290)
at com.opencsv.bean.AbstractBeanField.setFieldValue(AbstractBeanField.java:182)
at com.opencsv.bean.AbstractMappingStrategy.setFieldValue(AbstractMappingStrategy.java:607)
at com.opencsv.bean.AbstractMappingStrategy.populateNewBean(AbstractMappingStrategy.java:330)
at com.opencsv.bean.concurrent.ProcessCsvLine.processLine(ProcessCsvLine.java:131)
at com.opencsv.bean.concurrent.ProcessCsvLine.run(ProcessCsvLine.java:87)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
at java.base/java.lang.Thread.run(Thread.java:834)
Caused by: java.lang.reflect.InvocationTargetException
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:566)
at com.opencsv.bean.FieldAccess.lambda$determineAssignmentMethod$3(FieldAccess.java:79)
at com.opencsv.bean.FieldAccess.setField(FieldAccess.java:115)
at com.opencsv.bean.AbstractBeanField.assignValueToField(AbstractBeanField.java:286)
... 8 more
Caused by: com.opencsv.exceptions.CsvValidationException: 'Contact First Name' must be between 3-8 characters long
at org.lotia.example.entity.Contact.setContactFirstName(Contact.java:23)
... 15 more
Process finished with exit code 255