Spring Batch ChunkRequest throws stackOverflow - spring-boot

I am struggling with Spring Batch RemoteChunking with newer versions of Spring boot.
First i try to send ChunkRequest as event, it wasn't possible because it has no public default constructor. As solution I had to create a custom serializer and Deserializer and I set them in my application.properties correctly.
After doing all of that, now i am having Stackoverflow. (i understand the reason just by checking the ChunkRequest class which Has Collection of stepExecutions and the step execution have jobExecution which have stepExecutions)
https://docs.spring.io/spring-batch/docs/current/api/org/springframework/batch/integration/chunk/ChunkRequest.html
What i am missing, even after serializing ChunkRequest as byte[]?
2022-05-14 00:22:31.880 INFO 11974 --- [container-0-C-1] o.a.k.c.c.internals.ConsumerCoordinator : [Consumer clientId=consumer-anonymous.3ac5789f-01ba-493f-a7ce-6f6f4429a0a1-2, groupId=anonymous.3ac5789f-01ba-493f-a7ce-6f6f4429a0a1] (Re-)joining group
2022-05-14 00:22:31.891 INFO 11974 --- [ main] o.s.b.c.l.support.SimpleJobLauncher : Job: [SimpleJob: [name=client-job]] launched with the following parameters: [{run.id=1}]
2022-05-14 00:22:31.901 INFO 11974 --- [ main] o.s.batch.core.job.SimpleStepHandler : Executing step: [dispatchStep]
2022-05-14 00:22:31.948 ERROR 11974 --- [ main] o.s.batch.core.step.AbstractStep : Encountered an error executing step dispatchStep in job client-job
org.springframework.retry.ExhaustedRetryException: Retry exhausted after last attempt in recovery path, but exception is not skippable.; nested exception is org.springframework.messaging.MessageDeliveryException: failed to send Message to channel 'clientRequests'; nested exception is org.springframework.messaging.converter.MessageConversionException: Could not write JSON: Infinite recursion (StackOverflowError) (through reference chain: org.springframework.batch.core.JobExecution["stepExecutions"]->java.util.Collections$UnmodifiableRandomAccessList[0]->org.springframework.batch.core.StepExecution["jobExecution"]->org.springframework.batch.core.JobExecution["stepExecutions"]->org.springframework.batch.core.StepExecution["jobExecution"]->org.springframework.batch.core.StepExecution["jobExecution"]->java.util.Collections$UnmodifiableRandomAccessList[0]->org.springframework.batch.core.StepExecution["jobExecution"]->org.springframework.batch.core.JobExecution["stepExecutions"]->java.util.Collections$UnmodifiableRandomAccessList[0]->org.springframework.batch.core.StepExecution["jobExecution"]->org.springframework.batch.core.JobExecution["stepExecutions"]->java.util.Collections$UnmodifiableRandomAccessList[0]->org.springframework.batch.core.StepExecution["jobExecution"]->org.springframework.batch.core.JobExecution["stepExecutions"]->java.util.Collections$UnmodifiableRandomAccessList[0]->org.springframework.batch.core.StepExecution["jobExecution"]->org.springframework.batch.core.JobExecution["stepExecutions"]->java.util.Collections$UnmodifiableRandomAccessList[0]->org.springframework.batch.core.StepExecution["jobExecution"]->org.springframework.batch.core.JobExecution["stepExecutions"]->java.util.Collections$UnmodifiableRandomAccessList[0]->org.springframework.batch.core.StepExecution["jobExecution"]->org.springframework.batch.core.JobExecution["stepExecutions"]->java.util.Collections$UnmodifiableRandomAccessList[0]->org.springframework.batch.core.StepExecution["jobExecution"]->org.springframework.batch.core.JobExecution["stepExecutions"]->java.util.Collections$UnmodifiableRandomAccessList[0]->org.springframework.batch.core.StepExecution["jobExecution"]->org.springframework.batch.core.JobExecution["stepExecutions"]->java.util.Collections$UnmodifiableRandomAccessList[0]->org.springframework.batch.core.StepExecution["jobExecution"]->org.springframework.batch.core.JobExecution["stepExecutions"]->java.util.Collections$UnmodifiableRandomAccessList[0]->org.springframework.batch.core.StepExecution["jobExecution"]->org.springframework.batch.core.JobExecution["stepExecutions"]->java.util.Collections$UnmodifiableRandomAccessList[0]->org.springframework.batch.core.StepExecution["jobExecution"]->org.springframework.batch.core.JobExecution["stepExecutions"]); nested exception is com.fasterxml.jackson.databind.JsonMappingException: Infinite recursion (StackOverflowError) (through reference chain: org.springframework.batch.core.JobExecution["stepExecutions"]->java.util.Collections$UnmodifiableRandomAccessList[0]->org.springframework.batch.core.StepExecution["jobExecution"]->org.springframework.batch.core.JobExecution["stepExecutions"]->java.util.Collections$UnmodifiableRandomAccessList[0]->org.springframework.batch.core.StepExecution["jobExecution"]->org.springframework.batch.core.JobExecution["stepExecutions"]->java.util.Collections$UnmodifiableRandomAccessList[0]->org.springframework.batch.core.StepExecution["jobExecution"]->org.springframework.batch.core.JobExecution["stepExecutions"]->java.util.Collections$UnmodifiableRandomAccessList[0]->org.springframework.batch.core.StepExecution["jobExecution"]->org.springframework.batch.core.JobExecution["stepExecutions"]->java.util
.Collections$UnmodifiableRandomAccessList[0]->org.springframework.batch.core.StepExecution["jobExecution"]->org.springframework.batch.core.JobExecution["stepExecutions"]), failedMessage=GenericMessage [payload=ChunkRequest: jobId=1, sequence=0, contribution=[StepContribution: read=0, written=0, filtered=0, readSkips=0, writeSkips=0, processSkips=0, exitStatus=EXECUTING], item count=1, headers={id=ae9dbd76-ed32-0410-dacd-b6c700de87b2, contentType=application/json, timestamp=1652484151911}]
at org.springframework.batch.core.step.item.FaultTolerantChunkProcessor$5.recover(FaultTolerantChunkProcessor.java:429) ~[spring-batch-core-4.3.5.jar:4.3.5]
at org.springframework.retry.support.RetryTemplate.handleRetryExhausted(RetryTemplate.java:539) ~[spring-retry-1.3.3.jar:na]
at org.springframework.retry.support.RetryTemplate.doExecute(RetryTemplate.java:387) ~[spring-retry-1.3.3.jar:na]
at org.springframework.retry.support.RetryTemplate.execute(RetryTemplate.java:255) ~[spring-retry-1.3.3.jar:na]
at org.springframework.batch.core.step.item.BatchRetryTemplate.execute(BatchRetryTemplate.java:217) ~[spring-batch-core-4.3.5.jar:4.3.5]
at org.springframework.batch.core.step.item.FaultTolerantChunkProcessor.write(FaultTolerantChunkProcessor.java:444) ~[spring-batch-core-4.3.5.jar:4.3.5]
at org.springframework.batch.core.step.item.SimpleChunkProcessor.process(SimpleChunkProcessor.java:217) ~[spring-batch-core-4.3.5.jar:4.3.5]
at org.springframework.batch.core.step.item.ChunkOrientedTasklet.execute(ChunkOrientedTasklet.java:77) ~[spring-batch-core-4.3.5.jar:4.3.5]
at org.springframework.batch.core.step.tasklet.TaskletStep$ChunkTransactionCallback.doInTransaction(TaskletStep.java:407) ~[spring-batch-core-4.3.5.jar:4.3.5]
at org.springframework.batch.core.step.tasklet.TaskletStep$ChunkTransactionCallback.doInTransaction(TaskletStep.java:331) ~[spring-batch-core-4.3.5.jar:4.3.5]
at org.springframework.transaction.support.TransactionTemplate.execute(TransactionTemplate.java:140) ~[spring-tx-5.3.19.jar:5.3.19]
at org.springframework.batch.core.step.tasklet.TaskletStep$2.doInChunkContext(TaskletStep.java:273) ~[spring-batch-core-4.3.5.jar:4.3.5]
at org.springframework.batch.core.scope.context.StepContextRepeatCallback.doInIteration(StepContextRepeatCallback.java:82) ~[spring-batch-core-4.3.5.jar:4.3.5]
at org.springframework.batch.repeat.support.RepeatTemplate.getNextResult(RepeatTemplate.java:375) ~[spring-batch-infrastructure-4.3.5.jar:4.3.5]
at org.springframework.batch.repeat.support.RepeatTemplate.executeInternal(RepeatTemplate.java:215) ~[spring-batch-infrastructure-4.3.5.jar:4.3.5]
at org.springframework.batch.repeat.support.RepeatTemplate.iterate(RepeatTemplate.java:145) ~[spring-batch-infrastructure-4.3.5.jar:4.3.5]
at org.springframework.batch.core.step.tasklet.TaskletStep.doExecute(TaskletStep.java:258) ~[spring-batch-core-4.3.5.jar:4.3.5]
at org.springframework.batch.core.step.AbstractStep.execute(AbstractStep.java:208) ~[spring-batch-core-4.3.5.jar:4.3.5]
at org.springframework.batch.core.job.SimpleStepHandler.handleStep(SimpleStepHandler.java:152) ~[spring-batch-core-4.3.5.jar:4.3.5]
at org.springframework.batch.core.job.AbstractJob.handleStep(AbstractJob.java:413) ~[spring-batch-core-4.3.5.jar:4.3.5]
at org.springframework.batch.core.job.SimpleJob.doExecute(SimpleJob.java:136) ~[spring-batch-core-4.3.5.jar:4.3.5]
at org.springframework.batch.core.job.AbstractJob.execute(AbstractJob.java:320) ~[spring-batch-core-4.3.5.jar:4.3.5]
org.springframework.boot.autoconfigure.batch.JobLauncherApplicationRunner.executeLocalJobs(JobLauncherApplicationRunner.java:173) ~[spring-boot-autoconfigure-2.6.7.jar:2.6.7]
at org.springframework.boot.autoconfigure.batch.JobLauncherApplicationRunner.launchJobFromProperties(JobLauncherApplicationRunner.java:160) ~[spring-boot-autoconfigure-2.6.7.jar:2.6.7]
at org.springframework.boot.autoconfigure.batch.JobLauncherApplicationRunner.run(JobLauncherApplicationRunner.java:155) ~[spring-boot-autoconfigure-2.6.7.jar:2.6.7]
at org.springframework.boot.autoconfigure.batch.JobLauncherApplicationRunner.run(JobLauncherApplicationRunner.java:150) ~[spring-boot-autoconfigure-2.6.7.jar:2.6.7]
at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:768) ~[spring-boot-2.6.7.jar:2.6.7]
at org.springframework.boot.SpringApplication.callRunners(SpringApplication.java:758) ~[spring-boot-2.6.7.jar:2.6.7]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:310) ~[spring-boot-2.6.7.jar:2.6.7]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1312) ~[spring-boot-2.6.7.jar:2.6.7]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1301) ~[spring-boot-2.6.7.jar:2.6.7]
at pt.bayonne.sensei.importclients.ImportClientsApplication.main(ImportClientsApplication.java:10) ~[classes/:na]
Caused by: org.springframework.messaging.MessageDeliveryException: failed to send Message to channel 'clientRequests'; nested exception is org.springframework.messaging.converter.MessageConversionException: Could not write JSON: Infinite recursion (StackOverflowError) (through reference chain: org.springframework.batch.core.JobExecution["stepExecutions"]->java.util.Collections$UnmodifiableRandomAccessList[0]->org.springframework.batch.core.StepExecution["jobExecution"]->org.springframework.batch.core.JobExecution["stepExecutions"]->java.util.Collections$UnmodifiableRandomAccessList[0]->org.springframework.batch.core.StepExecution["jobExecution"]->org.springframework.batch.core.JobExecution["stepExecutions"]->java.util.Collections$UnmodifiableRandomAccessList[0]->org.springframework.batch.core.StepExecution["jobExecution"]->org.springframework.batch.core.JobExecution["stepExecutions"]->java.util.Collections$UnmodifiableRandomAccessList[0]->org.springframework.batch.core.StepExecution["jobExecution"]->org.springframework.batch.core.JobExecution["stepExecutions"]->java.util
Any Idea? Any example of the sample of application using RemoteChunking? Thanks
After adding this:https://github.com/spring-projects/spring-batch/issues/1488
I got a new exception:
Caused by: java.io.StreamCorruptedException: invalid stream header: 7B0A2020
at java.base/java.io.ObjectInputStream.readStreamHeader(ObjectInputStream.java:963) ~[na:na]
at java.base/java.io.ObjectInputStream.<init>(ObjectInputStream.java:397) ~[na:na]
at org.springframework.util.SerializationUtils.deserialize(SerializationUtils.java:81) ~[spring-core-5.3.19.jar:5.3.19]
... 27 common frames omitted

i understand the reason just by checking the ChunkRequest class which Has Collection of stepExecutions and the step execution have jobExecution which have stepExecutions
You nailed it, and in the end you are hitting https://github.com/spring-projects/spring-batch/issues/1488. This is a Jackson issue, because other serialization mechanisms are able to serialize/deserialize ChunkRequest objects.

As #Mahmoud Ben Hassine mentioned,
This is a Jackson issue because other serialization mechanisms are
able to serialize/deserialize ChunkRequest objects.
Once you create your custom serializer, for example:
package pt.bayonne.sensei.RemoteChunking.job.serde;
import org.apache.kafka.common.serialization.Serializer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.batch.integration.chunk.ChunkRequest;
import org.springframework.util.SerializationUtils;
import pt.bayonne.sensei.RemoteChunking.dto.ClientDTO;
public class ChunkRequestSerializer implements Serializer<ChunkRequest>{
private static final Logger logger = LoggerFactory.getLogger(ChunkRequestSerializer.class);
#Override
public byte[] serialize(String topic, ChunkRequest data) {
if (data == null) {
return null;
}
String dataType = data.getClass().getName();
logger.debug("--> serializing: {}",dataType);
byte[] dataBytes = null;
try {
dataBytes = SerializationUtils.serialize(data);
} catch (Exception e) {
logger.error("Error serializing data", e);
}
return dataBytes;
}
}
You have to specify that it is using the native encoding.
#produces
spring.cloud.stream.bindings.clientRequests.destination=clientRequests
spring.cloud.stream.bindings.clientRequests.producer.use-native-encoding=true
spring.kafka.producer.value-serializer=pt.bayonne.sensei.RemoteChunking.job.serde.ChunkRequestSerializer
Otherwise you will have more exceptions and sometimes it will continue picking the default framework serializer/deserializer. Using the Mixins doesn't help that much

Related

Spring Batch / Azure Storage account blob resource [container"foo", blob='bar'] cannot be resolved to absolute file path

I am trying to write to an Azure Storage using Spring.
I am configuring the resource inside a Bean instead of Autowiring it from the Class.
BlobServiceClient client = new BlobServiceClientBuilder().connectionString(connectionString).endpoint(endpoint).buildClient();
Here is the blob name inside the Azure Storage Container:
String resourceString = "azure-blob://foo/bar.csv"
Set up the Azure Storage Pattern Resolver:
AzureStorageResourcePatternResolver storageResourcePatternResolver = new AzureStorageResourcePatternResolver(client);
Then get the Resouce:
Resource resource = storageResourcePatternResolver.getResource(resourceString);
This is the Error I am getting:
java.lang.UnsupportedOperationException: Azure storage account blob resource [container='foo', blob='bar.csv'] cannot be resolved to absolute file path
at com.azure.spring.autoconfigure.storage.resource.BlobStorageResource.getFile(BlobStorageResource.java:83) ~[azure-spring-boot-3.4.0.jar:na]
at org.springframework.batch.item.support.AbstractFileItemWriter.getOutputState(AbstractFileItemWriter.java:367) ~[spring-batch-infrastructure-4.3.2.jar:4.3.2]
at org.springframework.batch.item.support.AbstractFileItemWriter.open(AbstractFileItemWriter.java:308) ~[spring-batch-infrastructure-4.3.2.jar:4.3.2]
at org.springframework.batch.item.support.AbstractFileItemWriter$$FastClassBySpringCGLIB$$f2d35c3.invoke(<generated>) ~[spring-batch-infrastructure-4.3.2.jar:4.3.2]
at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218) ~[spring-core-5.3.5.jar:5.3.5]
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:779) ~[spring-aop-5.3.5.jar:5.3.5]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) ~[spring-aop-5.3.5.jar:5.3.5]
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:750) ~[spring-aop-5.3.5.jar:5.3.5]
at org.springframework.aop.support.DelegatingIntroductionInterceptor.doProceed(DelegatingIntroductionInterceptor.java:137) ~[spring-aop-5.3.5.jar:5.3.5]
at org.springframework.aop.support.DelegatingIntroductionInterceptor.invoke(DelegatingIntroductionInterceptor.java:124) ~[spring-aop-5.3.5.jar:5.3.5]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.3.5.jar:5.3.5]
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:750) ~[spring-aop-5.3.5.jar:5.3.5]
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:692) ~[spring-aop-5.3.5.jar:5.3.5]
at org.springframework.batch.item.file.FlatFileItemWriter$$EnhancerBySpringCGLIB$$5ce6a900.open(<generated>) ~[spring-batch-infrastructure-4.3.2.jar:4.3.2]
at org.springframework.batch.item.support.CompositeItemStream.open(CompositeItemStream.java:104) ~[spring-batch-infrastructure-4.3.2.jar:4.3.2]
at org.springframework.batch.core.step.tasklet.TaskletStep.open(TaskletStep.java:311) ~[spring-batch-core-4.3.2.jar:4.3.2]
at org.springframework.batch.core.step.AbstractStep.execute(AbstractStep.java:205) ~[spring-batch-core-4.3.2.jar:4.3.2]
at org.springframework.batch.core.partition.support.TaskExecutorPartitionHandler$1.call(TaskExecutorPartitionHandler.java:138) [spring-batch-core-4.3.2.jar:4.3.2]
at org.springframework.batch.core.partition.support.TaskExecutorPartitionHandler$1.call(TaskExecutorPartitionHandler.java:135) [spring-batch-core-4.3.2.jar:4.3.2]
at java.util.concurrent.FutureTask.run(FutureTask.java:266) [na:1.8.0_221]
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) [na:1.8.0_221]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) [na:1.8.0_221]
at java.lang.Thread.run(Thread.java:748) [na:1.8.0_221]2021-05-25 09:24:36.168 INFO 4916 --- [ taskExecutor-3] o.s.batch.core.step.AbstractStep : Step: [slaveStep:partition155] executed in 347ms2021-05-25 09:24:36.240 ERROR 4916 --- [ taskExecutor-1] o.s.batch.core.step.AbstractStep : Encountered an error executing step slaveStep in job job1
Any help is greatly appreciated.
The searchLocation should start with azure-blob:// or azure-file://. The "blob" in your comment is incorrect.
azure-blob://foo/bar.csv means the "bar.csv" blob in "foo" container. Please check your storage, make sure the blob exists.
For example, my blob URL is https://pamelastorage123.blob.core.windows.net/pamelac/test.txt, so azure-blob://pamelac/test.txt is right.
StorageExampleApplication.java:
#SpringBootApplication
public class StorageExampleApplication {
public static void main(String[] args) {
SpringApplication.run(StorageExampleApplication.class, args);
testRescource();
}
public static void testRescource(){
String searchLocation = "azure-blob://<container-name>/<blob-name>";
String connectionString = "<Connection string>";
String endpoint = "https://<account-name>.blob.core.windows.net";
BlobServiceClient client = new BlobServiceClientBuilder().connectionString(connectionString).endpoint(endpoint).buildClient();
AzureStorageResourcePatternResolver storageResourcePatternResolver = new AzureStorageResourcePatternResolver(client);
Resource resource = storageResourcePatternResolver.getResource(searchLocation);
System.out.println(resource.getFilename());
}
}
application.properties:
azure.storage.account-name=[storage-account-name]
azure.storage.account-key=[storage-account-access-key]
azure.storage.blob-endpoint=[storage-blob-endpoint-URL]
Result:
The FlatFileItemWriter is designed to work against any resource that represents a writable file. Here is an excerpt from the Javadoc:
The location of the output file is defined by a Resource and must represent
a writable file.
The initialization process of this writer checks if the passed resource is a writable file by calling Resource#getFile. In your case, the Resource implementation that you are using, ie BlobStorageResource throws a java.lang.UnsupportedOperationException for this operation, hence your error. You need to provide a Resource implementation that represents a file as expected by the FlatFileItemWriter.

Failed to convert property value of type 'java.lang.String' to required type in Spring Batch

I am working on a Spring Batch requirement. I am writing a converter class as a utility class in a separate util package in my project. I am reading the CSV file writing to MySQL database.
But I am facing issues like rejected value for field?
Domain Class
public class Customer implements Serializable {
private Integer id_type;
private String id_number;
private String customer_name;
private String email_address;
private LocalDate birthday;
private String citizenship;
private String address;
private Long msisdn;
private LocalDateTime kyc_date;
private String kyc_level;
private String goalscore;
private String mobile_network;
}
Utility Class
public final class StringToLocalDateConversion {
private StringToLocalDateConversion() {
}
static ConversionService createLocalDateConversionServicve() {
DefaultConversionService stringToLocalDateconversionService = new DefaultConversionService();
DefaultConversionService.addDefaultConverters(stringToLocalDateconversionService);
stringToLocalDateconversionService.addConverter(new Converter<String, LocalDate>() {
#Override
public LocalDate convert(String text) {
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-mm-dd");
return LocalDate.parse(text, formatter);
}
});
return stringToLocalDateconversionService;
}
}
public final class StringToLocalDateTimeConversion {
public StringToLocalDateTimeConversion() {
}
static ConversionService stringToLocalDateTimeConversionService() {
DefaultConversionService stringToLocalDateTimeConversion = new DefaultConversionService();
DefaultConversionService.addDefaultConverters(stringToLocalDateTimeConversion);
stringToLocalDateTimeConversion.addConverter(new Converter<String, LocalDateTime>() {
#Override
public LocalDateTime convert(String source) {
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-mm-dd hh:mm:ss");
return LocalDateTime.parse(source, dateTimeFormatter);
}
});
return stringToLocalDateTimeConversion;
}
}
BatchConfiguration Class
#Configuration
#EnableBatchProcessing
public class BatchConfiguration {
#Autowired
public JobBuilderFactory jobBuilderFactory;
#Autowired
public StepBuilderFactory stepBuilderFactory;
#Value("classPath:/data/gcash.csv")
private Resource inputResource;
#Autowired
public DataSource dataSource;
#Bean
public Job readCSVFilesJob() {
return jobBuilderFactory.get("readCSVFilesJob").incrementer(new RunIdIncrementer()).start(step1()).build();
}
#Bean
public Step step1() {
return stepBuilderFactory.get("step1").<Customer, Customer>chunk(10).reader(itemReader()).processor(processor())
.writer(writer()).build();
}
/*
* #Bean public DataSource dataSource() { final DriverManagerDataSource
* dataSource = new DriverManagerDataSource();
* dataSource.setDriverClassName("com.mysql.jdbc.Driver");
* dataSource.setUrl("jdbc:mysql://localhost:3306/springbatch");
* dataSource.setUsername("root"); dataSource.setPassword("123456");
*
* return dataSource; }
*/
#Bean
public ItemReader<Customer> itemReader() {
FlatFileItemReader<Customer> customerItemReader = new FlatFileItemReader<>();
customerItemReader.setName("CUSTOMER_READER");
customerItemReader.setLineMapper(linemapper());
customerItemReader.setLinesToSkip(1);
customerItemReader.setResource(inputResource);
return customerItemReader;
}
#Bean
public LineMapper<Customer> linemapper() {
DefaultLineMapper<Customer> linemapper = new DefaultLineMapper<>();
final DelimitedLineTokenizer tokenizer = new DelimitedLineTokenizer();
tokenizer.setDelimiter(";");
tokenizer.setStrict(false);
tokenizer.setNames(new String[] { "id_type", "id_number", "customer_name", "email_address", "birthday",
"citizenship", "address", "msisdn", "kyc_date", "kyc_level", "goalscore", "mobile_network" });
linemapper.setLineTokenizer(tokenizer);
BeanWrapperFieldSetMapper<Customer> fieldSetMapper = new BeanWrapperFieldSetMapper<>();
fieldSetMapper.setTargetType(Customer.class);
ConversionService localDateConversionService = StringToLocalDateConversion.createLocalDateConversionServicve();
ConversionService localDateTimeConversionService = StringToLocalDateTimeConversion
.stringToLocalDateTimeConversionService();
fieldSetMapper.setConversionService(localDateConversionService);
fieldSetMapper.setConversionService(localDateTimeConversionService);
linemapper.setFieldSetMapper(fieldSetMapper);
return linemapper;
}
#Bean
public CustomerItemProcessor processor() {
return new CustomerItemProcessor();
}
#Bean
public JdbcBatchItemWriter<Customer> writer() {
JdbcBatchItemWriter<Customer> writer = new JdbcBatchItemWriter<>();
writer.setItemSqlParameterSourceProvider(new BeanPropertyItemSqlParameterSourceProvider<Customer>());
writer.setSql(
"INSERT INTO people (id_type, id_number,customer_name,email_address,birthday,citizenship,address,msisdn,kyc_date,kyc_level,goalscore,mobile_network) VALUES (:id_type, :id_number, :customer_name, :email_address, :birthday, :citizenship, :address, :msisdn, :kyc_date, :goalscore, :mobile_network)");
writer.setDataSource(this.dataSource);
return writer;
}
}
StackTrace
org.springframework.batch.item.file.FlatFileParseException: Parsing error at line: 2 in resource=[URL [classpath:/data/gcash.csv]], input=["LISONDRA, MARIA MINI, JUCOM",MJLISONDRA71#GMAIL.COM,1971-02-12,FILIPINO,2,06-1401967-8,"M L QUEZON CABANCALAN, QUEZON, MANDAUE",9052100646,2019-10-10 11:45:18,FULL KYC,525_549,Globe Prepaid]
at org.springframework.batch.item.file.FlatFileItemReader.doRead(FlatFileItemReader.java:189) ~[spring-batch-infrastructure-4.3.1.jar:4.3.1]
at org.springframework.batch.item.support.AbstractItemCountingItemStreamItemReader.read(AbstractItemCountingItemStreamItemReader.java:93) ~[spring-batch-infrastructure-4.3.1.jar:4.3.1]
at org.springframework.batch.core.step.item.SimpleChunkProvider.doRead(SimpleChunkProvider.java:99) ~[spring-batch-core-4.3.1.jar:4.3.1]
at org.springframework.batch.core.step.item.SimpleChunkProvider.read(SimpleChunkProvider.java:180) ~[spring-batch-core-4.3.1.jar:4.3.1]
at org.springframework.batch.core.step.item.SimpleChunkProvider$1.doInIteration(SimpleChunkProvider.java:126) ~[spring-batch-core-4.3.1.jar:4.3.1]
at org.springframework.batch.repeat.support.RepeatTemplate.getNextResult(RepeatTemplate.java:375) ~[spring-batch-infrastructure-4.3.1.jar:4.3.1]
at org.springframework.batch.repeat.support.RepeatTemplate.executeInternal(RepeatTemplate.java:215) ~[spring-batch-infrastructure-4.3.1.jar:4.3.1]
at org.springframework.batch.repeat.support.RepeatTemplate.iterate(RepeatTemplate.java:145) ~[spring-batch-infrastructure-4.3.1.jar:4.3.1]
at org.springframework.batch.core.step.item.SimpleChunkProvider.provide(SimpleChunkProvider.java:118) ~[spring-batch-core-4.3.1.jar:4.3.1]
at org.springframework.batch.core.step.item.ChunkOrientedTasklet.execute(ChunkOrientedTasklet.java:71) ~[spring-batch-core-4.3.1.jar:4.3.1]
at org.springframework.batch.core.step.tasklet.TaskletStep$ChunkTransactionCallback.doInTransaction(TaskletStep.java:407) ~[spring-batch-core-4.3.1.jar:4.3.1]
at org.springframework.batch.core.step.tasklet.TaskletStep$ChunkTransactionCallback.doInTransaction(TaskletStep.java:331) ~[spring-batch-core-4.3.1.jar:4.3.1]
at org.springframework.transaction.support.TransactionTemplate.execute(TransactionTemplate.java:140) ~[spring-tx-5.3.4.jar:5.3.4]
at org.springframework.batch.core.step.tasklet.TaskletStep$2.doInChunkContext(TaskletStep.java:273) ~[spring-batch-core-4.3.1.jar:4.3.1]
at org.springframework.batch.core.scope.context.StepContextRepeatCallback.doInIteration(StepContextRepeatCallback.java:82) ~[spring-batch-core-4.3.1.jar:4.3.1]
at org.springframework.batch.repeat.support.RepeatTemplate.getNextResult(RepeatTemplate.java:375) ~[spring-batch-infrastructure-4.3.1.jar:4.3.1]
at org.springframework.batch.repeat.support.RepeatTemplate.executeInternal(RepeatTemplate.java:215) ~[spring-batch-infrastructure-4.3.1.jar:4.3.1]
at org.springframework.batch.repeat.support.RepeatTemplate.iterate(RepeatTemplate.java:145) ~[spring-batch-infrastructure-4.3.1.jar:4.3.1]
at org.springframework.batch.core.step.tasklet.TaskletStep.doExecute(TaskletStep.java:258) ~[spring-batch-core-4.3.1.jar:4.3.1]
at org.springframework.batch.core.step.AbstractStep.execute(AbstractStep.java:208) ~[spring-batch-core-4.3.1.jar:4.3.1]
at org.springframework.batch.core.job.SimpleStepHandler.handleStep(SimpleStepHandler.java:148) [spring-batch-core-4.3.1.jar:4.3.1]
at org.springframework.batch.core.job.AbstractJob.handleStep(AbstractJob.java:411) [spring-batch-core-4.3.1.jar:4.3.1]
at org.springframework.batch.core.job.SimpleJob.doExecute(SimpleJob.java:136) [spring-batch-core-4.3.1.jar:4.3.1]
at org.springframework.batch.core.job.AbstractJob.execute(AbstractJob.java:320) [spring-batch-core-4.3.1.jar:4.3.1]
at org.springframework.batch.core.launch.support.SimpleJobLauncher$1.run(SimpleJobLauncher.java:147) [spring-batch-core-4.3.1.jar:4.3.1]
at org.springframework.core.task.SyncTaskExecutor.execute(SyncTaskExecutor.java:50) [spring-core-5.3.4.jar:5.3.4]
at org.springframework.batch.core.launch.support.SimpleJobLauncher.run(SimpleJobLauncher.java:140) [spring-batch-core-4.3.1.jar:4.3.1]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_271]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_271]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_271]
at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_271]
at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:344) [spring-aop-5.3.4.jar:5.3.4]
at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:198) [spring-aop-5.3.4.jar:5.3.4]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) [spring-aop-5.3.4.jar:5.3.4]
at org.springframework.batch.core.configuration.annotation.SimpleBatchConfiguration$PassthruAdvice.invoke(SimpleBatchConfiguration.java:128) [spring-batch-core-4.3.1.jar:4.3.1]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) [spring-aop-5.3.4.jar:5.3.4]
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:215) [spring-aop-5.3.4.jar:5.3.4]
at com.sun.proxy.$Proxy104.run(Unknown Source) [na:na]
at org.springframework.boot.autoconfigure.batch.JobLauncherApplicationRunner.execute(JobLauncherApplicationRunner.java:199) [spring-boot-autoconfigure-2.4.3.jar:2.4.3]
at org.springframework.boot.autoconfigure.batch.JobLauncherApplicationRunner.executeLocalJobs(JobLauncherApplicationRunner.java:173) [spring-boot-autoconfigure-2.4.3.jar:2.4.3]
at org.springframework.boot.autoconfigure.batch.JobLauncherApplicationRunner.launchJobFromProperties(JobLauncherApplicationRunner.java:160) [spring-boot-autoconfigure-2.4.3.jar:2.4.3]
at org.springframework.boot.autoconfigure.batch.JobLauncherApplicationRunner.run(JobLauncherApplicationRunner.java:155) [spring-boot-autoconfigure-2.4.3.jar:2.4.3]
at org.springframework.boot.autoconfigure.batch.JobLauncherApplicationRunner.run(JobLauncherApplicationRunner.java:150) [spring-boot-autoconfigure-2.4.3.jar:2.4.3]
at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:795) [spring-boot-2.4.3.jar:2.4.3]
at org.springframework.boot.SpringApplication.callRunners(SpringApplication.java:785) [spring-boot-2.4.3.jar:2.4.3]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:333) [spring-boot-2.4.3.jar:2.4.3]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1311) [spring-boot-2.4.3.jar:2.4.3]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1300) [spring-boot-2.4.3.jar:2.4.3]
at com.gcash.milo.GCashMiloApplication.main(GCashMiloApplication.java:10) [classes/:na]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_271]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_271]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_271]
at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_271]
at org.springframework.boot.devtools.restart.RestartLauncher.run(RestartLauncher.java:49) [spring-boot-devtools-2.4.3.jar:2.4.3]
Caused by: org.springframework.validation.BindException: org.springframework.validation.BeanPropertyBindingResult: 3 errors
Field error in object 'target' on field 'id_type': rejected value ["LISONDRA, MARIA MINI, JUCOM",MJLISONDRA71#GMAIL.COM,1971-02-12,FILIPINO,2,06-1401967-8,"M L QUEZON CABANCALAN, QUEZON, MANDAUE",9052100646,2019-10-10 11:45:18,FULL KYC,525_549,Globe Prepaid]; codes [typeMismatch.target.id_type,typeMismatch.id_type,typeMismatch.java.lang.Integer,typeMismatch]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [target.id_type,id_type]; arguments []; default message [id_type]]; default message [Failed to convert property value of type 'java.lang.String' to required type 'java.lang.Integer' for property 'id_type'; nested exception is java.lang.NumberFormatException: For input string: ""LISONDRA,MARIAMINI,JUCOM",MJLISONDRA71#GMAIL.COM,1971-02-12,FILIPINO,2,06-1401967-8,"MLQUEZONCABANCALAN,QUEZON,MANDAUE",9052100646,2019-10-1011:45:18,FULLKYC,525_549,GlobePrepaid"]
Field error in object 'target' on field 'kyc_date': rejected value []; codes [typeMismatch.target.kyc_date,typeMismatch.kyc_date,typeMismatch.java.time.LocalDateTime,typeMismatch]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [target.kyc_date,kyc_date]; arguments []; default message [kyc_date]]; default message [Failed to convert property value of type 'java.lang.String' to required type 'java.time.LocalDateTime' for property 'kyc_date'; nested exception is org.springframework.core.convert.ConversionFailedException: Failed to convert from type [java.lang.String] to type [java.time.LocalDateTime] for value ''; nested exception is java.time.format.DateTimeParseException: Text '' could not be parsed at index 0]
Field error in object 'target' on field 'birthday': rejected value []; codes [typeMismatch.target.birthday,typeMismatch.birthday,typeMismatch.java.time.LocalDate,typeMismatch]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [target.birthday,birthday]; arguments []; default message [birthday]]; default message [Failed to convert property value of type 'java.lang.String' to required type 'java.time.LocalDate' for property 'birthday'; nested exception is java.lang.IllegalStateException: Cannot convert value of type 'java.lang.String' to required type 'java.time.LocalDate' for property 'birthday': no matching editors or conversion strategy found]
at org.springframework.batch.item.file.mapping.BeanWrapperFieldSetMapper.mapFieldSet(BeanWrapperFieldSetMapper.java:201) ~[spring-batch-infrastructure-4.3.1.jar:4.3.1]
at org.springframework.batch.item.file.mapping.DefaultLineMapper.mapLine(DefaultLineMapper.java:43) ~[spring-batch-infrastructure-4.3.1.jar:4.3.1]
at org.springframework.batch.item.file.FlatFileItemReader.doRead(FlatFileItemReader.java:185) ~[spring-batch-infrastructure-4.3.1.jar:4.3.1]
... 53 common frames omitted
[2m2021-04-27 22:45:46.085[0;39m [32m INFO[0;39m [35m7456[0;39m [2m---[0;39m [2m[ restartedMain][0;39m [36mo.s.batch.core.step.AbstractStep [0;39m [2m:[0;39m Step: [step1] executed in 25ms
[2m2021-04-27 22:45:46.097[0;39m [32m INFO[0;39m [35m7456[0;39m [2m---[0;39m [2m[ restartedMain][0;39m [36mo.s.b.c.l.support.SimpleJobLauncher [0;39m [2m:[0;39m Job: [SimpleJob: [name=readCSVFilesJob]] completed with the following parameters: [{run.id=17}] and the following status: [FAILED] in 49ms
[2m2021-04-27 22:45:46.097[0;39m [32m INFO[0;39m [35m7456[0;39m [2m---[0;39m [2m[ restartedMain][0;39m [36m.ConditionEvaluationDeltaLoggingListener[0;39m [2m:[0;39m Condition evaluation unchanged
Well if you see my domain class three fields id_type,birthday,kyc_date, have taken them as Integer, LocalDate, LocalDateTime. For this i have also written Converter class. but i am getting three different errors.
Caused by: org.springframework.validation.BindException: org.springframework.validation.BeanPropertyBindingResult: 3 errors
Field error in object 'target' on field 'id_type': rejected value ["LISONDRA, MARIA MINI, JUCOM",MJLISONDRA71#GMAIL.COM,1971-02-12,FILIPINO,2,06-1401967-8,"M L QUEZON CABANCALAN, QUEZON, MANDAUE",9052100646,2019-10-10 11:45:18,FULL KYC,525_549,Globe Prepaid]; codes [typeMismatch.target.id_type,typeMismatch.id_type,typeMismatch.java.lang.Integer,typeMismatch]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [target.id_type,id_type]; arguments []; default message [id_type]]; default message [Failed to convert property value of type 'java.lang.String' to required type 'java.lang.Integer' for property 'id_type'; nested exception is java.lang.NumberFormatException: For input string: ""LISONDRA,MARIAMINI,JUCOM",MJLISONDRA71#GMAIL.COM,1971-02-12,FILIPINO,2,06-1401967-8,"MLQUEZONCABANCALAN,QUEZON,MANDAUE",9052100646,2019-10-1011:45:18,FULLKYC,525_549,GlobePrepaid"]
Field error in object 'target' on field 'kyc_date': rejected value []; codes [typeMismatch.target.kyc_date,typeMismatch.kyc_date,typeMismatch.java.time.LocalDateTime,typeMismatch]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [target.kyc_date,kyc_date]; arguments []; default message [kyc_date]]; default message [Failed to convert property value of type 'java.lang.String' to required type 'java.time.LocalDateTime' for property 'kyc_date'; nested exception is org.springframework.core.convert.ConversionFailedException: Failed to convert from type [java.lang.String] to type [java.time.LocalDateTime] for value ''; nested exception is java.time.format.DateTimeParseException: Text '' could not be parsed at index 0]
Field error in object 'target' on field 'birthday': rejected value []; codes [typeMismatch.target.birthday,typeMismatch.birthday,typeMismatch.java.time.LocalDate,typeMismatch]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [target.birthday,birthday]; arguments []; default message [birthday]]; default message [Failed to convert property value of type 'java.lang.String' to required type 'java.time.LocalDate' for property 'birthday'; nested exception is java.lang.IllegalStateException: Cannot convert value of type 'java.lang.String' to required type 'java.time.LocalDate' for property 'birthday': no matching editors or conversion strategy found]
I am having trouble understanding this error:
[Failed to convert property value of type 'java.lang.String' to required type 'java.lang.Integer' for property 'id_type'
In my model class , id_type is of type Integer, then why it is saying "Failed to convert property value string to Integer?"
This is because you have line where some fields contain the delimiter (,) inside a quoted field:
"LISONDRA, MARIA MINI, JUCOM",MJLISONDRA71#GMAIL.COM,1971-02-12,FILIPINO,2,06-1401967-8,"M L QUEZON CABANCALAN, QUEZON, MANDAUE",9052100646,2019-10-10 11:45:18,FULL KYC,525_549,Globe Prepaid
Since you are using the DelimitedLineTokenizer in which the default quote character is ", the fields "LISONDRA, MARIA MINI, JUCOM" and "M L QUEZON CABANCALAN, QUEZON, MANDAUE" are not considered as a single value. Hence, the entire line as a String is attempted to be converted to the first field which type_id of type Integer. There is an open issue for that here: https://github.com/spring-projects/spring-batch/issues/1822.
You need to use a different quote character or create a custom FieldSetMapper that is able to handle this case.
EDIT: add example for conversion service
conversionService.addConverter(new Converter<String, LocalDate>() { .. });
conversionService.addConverter(new Converter<String, LocalDatTime>() { .. });
fieldSetMapper.setConversionService(conversionService);

Spring Boot replacing application property on startup

In my Spring Boot application I need to replace some properties defined in application.yml with the ones from AWS Secrets Manager. I am aware of Spring Cloud AWS Secrets Manager project, but for various reasons using it is not an option for me. I decided implement a listener which would listen to ApplicationEnvironmentPreparedEvent and replace all the properties I need. The problem is that I am getting a strange exception which I cannot explain. Here is my code (It is a bit messy since I experimented with it.
I know by experimenting that the PropertySource of application.yml is always instance of MapPropertySource
Replacing property within PropertySource is not an option since the map within it is immutable, I need to replace the entire PropertySource with a new one containing modified properties
The properties within PropertySource map are instances of OriginTrackedValue, so I need to construct them
#Component
#Slf4j
public class PropertiesListener implements ApplicationListener<ApplicationEnvironmentPreparedEvent> {
#Override
public void onApplicationEvent(ApplicationEnvironmentPreparedEvent event) {
ConfigurableEnvironment environment = event.getEnvironment();
MutablePropertySources propertySources = environment.getPropertySources();
Iterator<PropertySource<?>> iterator = propertySources.iterator();
while (iterator.hasNext()) {
PropertySource<?> propertySource = iterator.next();
PropertySource<?> replacement = replaceWithSecrets(propertySource);
if (replacement != null) {
propertySources.remove(propertySource.getName());
propertySources.addLast(replacement);
}
}
}
private PropertySource<?> replaceWithSecrets(PropertySource<?> originalPropertySource) {
boolean needsReplacement = false;
Map<String, Object> newMap = new HashMap<>();
MapPropertySource map = null;
if (originalPropertySource instanceof MapPropertySource) {
map = (MapPropertySource) originalPropertySource;
for (Map.Entry<String, Object> entry : map.getSource().entrySet()) {
if (needsReplacement(entry.getValue().toString())) {
Origin origin = OriginLookup.getOrigin(originalPropertySource, entry.getKey());
OriginTrackedValue val = OriginTrackedValue.of(replaceWithSecret(entry.getValue().toString()), origin);
newMap.put(entry.getKey(), val);
needsReplacement = true;
} else {
newMap.put(entry.getKey(), entry.getValue());
}
}
if (needsReplacement) {
return new MapPropertySource(originalPropertySource.getName(), Collections.unmodifiableMap(newMap));
} else {
return null;
}
}
On startup my application throws an exception
12:51:25.523 [main] ERROR o.s.boot.SpringApplication - Application run failed
org.springframework.beans.factory.BeanDefinitionStoreException: Failed to process import candidates for configuration class [org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration]; nested exception is java.lang.IllegalStateException: Error processing condition on org.springframework.boot.autoconfigure.orm.jpa.JpaBaseConfiguration$JpaWebConfiguration
at org.springframework.context.annotation.ConfigurationClassParser.processImports(ConfigurationClassParser.java:610)
at org.springframework.context.annotation.ConfigurationClassParser.doProcessConfigurationClass(ConfigurationClassParser.java:311)
at org.springframework.context.annotation.ConfigurationClassParser.processConfigurationClass(ConfigurationClassParser.java:250)
at org.springframework.context.annotation.ConfigurationClassParser.processImports(ConfigurationClassParser.java:600)
at org.springframework.context.annotation.ConfigurationClassParser.access$800(ConfigurationClassParser.java:111)
at org.springframework.context.annotation.ConfigurationClassParser$DeferredImportSelectorGroupingHandler.lambda$processGroupImports$1(ConfigurationClassParser.java:812)
at java.util.ArrayList.forEach(ArrayList.java:1257)
at org.springframework.context.annotation.ConfigurationClassParser$DeferredImportSelectorGroupingHandler.processGroupImports(ConfigurationClassParser.java:809)
at org.springframework.context.annotation.ConfigurationClassParser$DeferredImportSelectorHandler.process(ConfigurationClassParser.java:780)
at org.springframework.context.annotation.ConfigurationClassParser.parse(ConfigurationClassParser.java:193)
at org.springframework.context.annotation.ConfigurationClassPostProcessor.processConfigBeanDefinitions(ConfigurationClassPostProcessor.java:331)
at org.springframework.context.annotation.ConfigurationClassPostProcessor.postProcessBeanDefinitionRegistry(ConfigurationClassPostProcessor.java:247)
at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanDefinitionRegistryPostProcessors(PostProcessorRegistrationDelegate.java:311)
at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(PostProcessorRegistrationDelegate.java:112)
at org.springframework.context.support.AbstractApplicationContext.invokeBeanFactoryPostProcessors(AbstractApplicationContext.java:746)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:564)
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:144)
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:769)
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:761)
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:426)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:326)
at com.ewc.inventory.EwcInventoryApplication.main(EwcInventoryApplication.java:24)
Caused by: java.lang.IllegalStateException: Error processing condition on org.springframework.boot.autoconfigure.orm.jpa.JpaBaseConfiguration$JpaWebConfiguration
at org.springframework.boot.autoconfigure.condition.SpringBootCondition.matches(SpringBootCondition.java:60)
at org.springframework.context.annotation.ConditionEvaluator.shouldSkip(ConditionEvaluator.java:108)
at org.springframework.context.annotation.ConfigurationClassParser.processConfigurationClass(ConfigurationClassParser.java:226)
at org.springframework.context.annotation.ConfigurationClassParser.processMemberClasses(ConfigurationClassParser.java:372)
at org.springframework.context.annotation.ConfigurationClassParser.doProcessConfigurationClass(ConfigurationClassParser.java:272)
at org.springframework.context.annotation.ConfigurationClassParser.processConfigurationClass(ConfigurationClassParser.java:250)
at org.springframework.context.annotation.ConfigurationClassParser.processImports(ConfigurationClassParser.java:600)
... 21 common frames omitted
Caused by: org.springframework.core.convert.ConverterNotFoundException: No converter found capable of converting from type [org.springframework.boot.origin.OriginTrackedValue] to type [java.lang.String]
at org.springframework.core.convert.support.GenericConversionService.handleConverterNotFound(GenericConversionService.java:322)
at org.springframework.core.convert.support.GenericConversionService.convert(GenericConversionService.java:195)
at org.springframework.core.convert.support.GenericConversionService.convert(GenericConversionService.java:175)
at org.springframework.core.env.AbstractPropertyResolver.convertValueIfNecessary(AbstractPropertyResolver.java:265)
at org.springframework.core.env.PropertySourcesPropertyResolver.getProperty(PropertySourcesPropertyResolver.java:91)
at org.springframework.core.env.PropertySourcesPropertyResolver.getProperty(PropertySourcesPropertyResolver.java:62)
at org.springframework.core.env.AbstractEnvironment.getProperty(AbstractEnvironment.java:588)
at org.springframework.boot.autoconfigure.condition.OnPropertyCondition$Spec.collectProperties(OnPropertyCondition.java:140)
at org.springframework.boot.autoconfigure.condition.OnPropertyCondition$Spec.access$000(OnPropertyCondition.java:105)
at org.springframework.boot.autoconfigure.condition.OnPropertyCondition.determineOutcome(OnPropertyCondition.java:91)
at org.springframework.boot.autoconfigure.condition.OnPropertyCondition.getMatchOutcome(OnPropertyCondition.java:55)
at org.springframework.boot.autoconfigure.condition.SpringBootCondition.matches(SpringBootCondition.java:47)
... 27 common frames omitted
The root cause seems to be
org.springframework.core.convert.ConverterNotFoundException: No converter found capable of converting from type [org.springframework.boot.origin.OriginTrackedValue] to type [java.lang.String]
at org.springframework.core.convert.support.GenericConversionService.handleConverterNotFound(GenericConversionService.java:322)
I tried to change the code around, by adding the string directly to PropertySource map instead of OriginTrackedValue, construct OriginTrackedValue in different way, but I am still getting the same exception. I am getting it even if I construct new MapPropertySource with the map from old property source.

Pagination and criteria for spring feign client

I'm stuck on setting up a feignclient of one of my microservices.
I use criteria (for filtering) and pagination.
On one of my microservices I have a service rest and the other use a feignclient to request it.
AccountCriteria (criteria interface from jhipster)
public class AccountCriteria implements Serializable, Criteria {
private LongFilter id;
private StringFilter user;
private LongFilter bankWebId;
private LongFilter bankApiId;
private LongFilter deactivationReasonId;
public AccountCriteria() {
}
public AccountCriteria(AccountCriteria other) {
this.id = other.id == null ? null : other.id.copy();
this.user = other.user == null ? null : other.user.copy();
this.bankWebId = other.bankWebId == null ? null : other.bankWebId.copy();
this.bankApiId = other.bankApiId == null ? null : other.bankApiId.copy();
this.deactivationReasonId = other.deactivationReasonId == null ? null : other.deactivationReasonId.copy();
}
#Override
public Criteria copy() {
return new AccountCriteria(this);
}
}
AccountIdentifierResource (Rest resource)
#RestController
#RequestMapping(value = "/api", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
public class AccountIdentifierResource {
log.debug("REST request to get AccountIdentifiers by criteria: {}", criteria);
Page<AccountIdentifier> page = accountIdentifierQueryService.findByCriteria(criteria, pageable);
HttpHeaders headers = PaginationUtil.generatePaginationHttpHeaders(uriBuilder.queryParams(queryParams), page);
return ResponseEntity.ok().headers(headers).body(page.getContent());
}
IdentityProviderFeignClient (feign client)
#AuthorizedFeignClient(name = "identityprovider")
public interface IdentityProviderFeignClient {
#GetMapping("/api/account-identifiers")
List<AccountIdentifier> getAllAccountIdentifiers(AccountCriteria criteria,
Pageable pageable, #RequestParam("queryParams") MultiValueMap<String, String> queryParams, UriComponentsBuilder uriBuilder);
}
IdentityProviderService (the service interface)
public interface IdentityProviderService {
List<AccountIdentifier> getAllAccountIdentifiers(AccountCriteria criteria, Pageable pageable, MultiValueMap<String, String> queryParams, UriComponentsBuilder uriBuilder);
}
IdentityProviderServiceImpl (the service implementation)
#Service
public class IdentityProviderServiceImpl implements IdentityProviderService {
private final Logger log =
LoggerFactory.getLogger(IdentityProviderServiceImpl.class);
private final IdentityProviderFeignClient identityProviderFeignClient;
public IdentityProviderServiceImpl(IdentityProviderFeignClient identityProviderFeignClient) {
this.identityProviderFeignClient = identityProviderFeignClient;
}
#Override
public List<AccountIdentifier> getAllAccountIdentifiers(AccountCriteria criteria, Pageable pageable, MultiValueMap<String, String> queryParams, UriComponentsBuilder uriBuilder) {
log.debug("Request to get all AccountIdentifier from IdentityProvider with criteria : {}", criteria);
return this.identityProviderFeignClient.getAllAccountIdentifiers(criteria, pageable, queryParams, uriBuilder);
}
}
FeignConfiguration
#Configuration
#EnableFeignClients(basePackages = "com.soft.jobstrategy")
#Import(FeignClientsConfiguration.class)
public class FeignConfiguration {
/**
* Set the Feign specific log level to log client REST requests.
*/
#Bean
feign.Logger.Level feignLoggerLevel() {
return feign.Logger.Level.BASIC;
}
}
For now it's impossible to run the application.
I get the following traceback:
[INFO] Running com.soft.jobstrategy.config.timezone.HibernateTimeZoneIT
:: JHipster ? :: Running Spring Boot 2.1.6.RELEASE ::
:: https://www.jhipster.tech ::
2019-10-04 16:07:44.465 WARN 2736 --- [ main] kafka.server.BrokerMetadataCheckpoint : No meta.properties file under dir C:\Users\maktouf\AppData\Local\Temp\kafka-6358187594718130765\meta.properties
2019-10-04 16:07:45.097 WARN 2736 --- [ main] kafka.server.BrokerMetadataCheckpoint : No meta.properties file under dir C:\Users\maktouf\AppData\Local\Temp\kafka-6358187594718130765\meta.properties
2019-10-04 16:07:45.343 INFO 2736 --- [ main] c.b.j.c.timezone.HibernateTimeZoneIT : No active profile set, falling back to default profiles: default
2019-10-04 16:07:49.628 WARN 2736 --- [ main] c.b.j.config.CacheConfiguration : No discovery service is set up, Hazelcast cannot create a cluster.
2019-10-04 16:07:51.266 WARN 2736 --- [ main] com.hazelcast.instance.Node : [192.168.1.21]:5701 [dev] [3.11.4] No join method is enabled! Starting standalone.
2019-10-04 16:07:57.509 WARN 2736 --- [ main] c.n.c.sources.URLConfigurationSource : No URLs will be polled as dynamic configuration sources.
2019-10-04 16:07:57.918 WARN 2736 --- [ main] o.s.w.c.s.GenericWebApplicationContext : Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creatin
g bean with name 'identityProviderServiceImpl' defined in file [C:\developpement\javaenv\workspace\job_strategy\target\classes\com\soft\jobstrategy\service\impl\IdentityProviderServiceImpl.class]: Unsatisfied dependency expressed through constructor par
ameter 0; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'com.soft.jobstrategy.client.IdentityProviderFeignClient': FactoryBean threw exception on object creation; nested exception is java.lang
.IllegalStateException: Method has too many Body parameters: public abstract java.util.List com.soft.jobstrategy.client.IdentityProviderFeignClient.getAllAccountIdentifiers(com.soft.jobstrategy.service.dto.AccountCriteria,org.springframework.dat
a.domain.Pageable,org.springframework.util.MultiValueMap,org.springframework.web.util.UriComponentsBuilder)
2019-10-04 16:07:57.965 INFO 2736 --- [ main] c.b.j.config.CacheConfiguration : Closing Cache Manager
2019-10-04 16:08:01.744 ERROR 2736 --- [ main] o.s.boot.SpringApplication : Application run failed
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'identityProviderServiceImpl' defined in file [C:\developpement\javaenv\workspace\job_strategy\target\classes\com\soft\jobstrategy\service\impl\IdentityProvi
derServiceImpl.class]: Unsatisfied dependency expressed through constructor parameter 0; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'com.soft.jobstrategy.client.IdentityProviderFeignClient'
: FactoryBean threw exception on object creation; nested exception is java.lang.IllegalStateException: Method has too many Body parameters: public abstract java.util.List com.soft.jobstrategy.client.IdentityProviderFeignClient.getAllAccountIdentifiers(c
om.soft.jobstrategy.service.dto.AccountCriteria,org.springframework.data.domain.Pageable,org.springframework.util.MultiValueMap,org.springframework.web.util.UriComponentsBuilder)
at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:769)
at org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:218)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireConstructor(AbstractAutowireCapableBeanFactory.java:1341)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1187)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:555)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:515)
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:320)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:318)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:845)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:877)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:549)
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:742)
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:389)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:311)
at org.springframework.boot.test.context.SpringBootContextLoader.loadContext(SpringBootContextLoader.java:119)
at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContextInternal(DefaultCacheAwareContextLoaderDelegate.java:99)
at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:117)
at org.springframework.test.context.support.DefaultTestContext.getApplicationContext(DefaultTestContext.java:108)
at org.springframework.test.context.web.ServletTestExecutionListener.setUpRequestContextIfNecessary(ServletTestExecutionListener.java:190)
at org.springframework.test.context.web.ServletTestExecutionListener.prepareTestInstance(ServletTestExecutionListener.java:132)
at org.springframework.test.context.TestContextManager.prepareTestInstance(TestContextManager.java:246)
at org.springframework.test.context.junit.jupiter.SpringExtension.postProcessTestInstance(SpringExtension.java:97)
at org.junit.jupiter.engine.descriptor.ClassTestDescriptor.lambda$invokeTestInstancePostProcessors$5(ClassTestDescriptor.java:349)
at org.junit.jupiter.engine.descriptor.JupiterTestDescriptor.executeAndMaskThrowable(JupiterTestDescriptor.java:215)
at org.junit.jupiter.engine.descriptor.ClassTestDescriptor.lambda$invokeTestInstancePostProcessors$6(ClassTestDescriptor.java:349)
at java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:193)
at java.util.stream.ReferencePipeline$2$1.accept(ReferencePipeline.java:175)
at java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1382)
at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:481)
at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:471)
at java.util.stream.StreamSpliterators$WrappingSpliterator.forEachRemaining(StreamSpliterators.java:312)
at java.util.stream.Streams$ConcatSpliterator.forEachRemaining(Streams.java:743)
at java.util.stream.Streams$ConcatSpliterator.forEachRemaining(Streams.java:742)
at java.util.stream.ReferencePipeline$Head.forEach(ReferencePipeline.java:580)
at org.junit.jupiter.engine.descriptor.ClassTestDescriptor.invokeTestInstancePostProcessors(ClassTestDescriptor.java:348)
at org.junit.jupiter.engine.descriptor.ClassTestDescriptor.instantiateAndPostProcessTestInstance(ClassTestDescriptor.java:270)
at org.junit.jupiter.engine.descriptor.ClassTestDescriptor.lambda$testInstanceProvider$2(ClassTestDescriptor.java:259)
at org.junit.jupiter.engine.descriptor.ClassTestDescriptor.lambda$testInstanceProvider$3(ClassTestDescriptor.java:263)
at java.util.Optional.orElseGet(Optional.java:267)
at org.junit.jupiter.engine.descriptor.ClassTestDescriptor.lambda$testInstanceProvider$4(ClassTestDescriptor.java:262)
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.prepare(TestMethodTestDescriptor.java:82)
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.prepare(TestMethodTestDescriptor.java:59)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$prepare$0(NodeTestTask.java:83)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:72)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.prepare(NodeTestTask.java:83)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:69)
at java.util.ArrayList.forEach(ArrayList.java:1257)
at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:38)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$4(NodeTestTask.java:112)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:72)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:98)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:74)
at java.util.ArrayList.forEach(ArrayList.java:1257)
at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:38)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$4(NodeTestTask.java:112)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:72)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:98)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:74)
at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:32)
at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57)
at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:51)
at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:220)
at org.junit.platform.launcher.core.DefaultLauncher.lambda$execute$6(DefaultLauncher.java:188)
at org.junit.platform.launcher.core.DefaultLauncher.withInterceptedStreams(DefaultLauncher.java:202)
at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:181)
at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:128)
at org.apache.maven.surefire.junitplatform.JUnitPlatformProvider.invokeAllTests(JUnitPlatformProvider.java:150)
at org.apache.maven.surefire.junitplatform.JUnitPlatformProvider.invoke(JUnitPlatformProvider.java:124)
at org.apache.maven.surefire.booter.ForkedBooter.invokeProviderInSameClassLoader(ForkedBooter.java:384)
at org.apache.maven.surefire.booter.ForkedBooter.runSuitesInProcess(ForkedBooter.java:345)
at org.apache.maven.surefire.booter.ForkedBooter.execute(ForkedBooter.java:126)
at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:418)
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'com.soft.jobstrategy.client.IdentityProviderFeignClient': FactoryBean threw exception on object creation; nested exception is java.lang.IllegalStateExcept
ion: Method has too many Body parameters: public abstract java.util.List com.soft.jobstrategy.client.IdentityProviderFeignClient.getAllAccountIdentifiers(com.soft.jobstrategy.service.dto.AccountCriteria,org.springframework.data.domain.Pageable,o
rg.springframework.util.MultiValueMap,org.springframework.web.util.UriComponentsBuilder)
at org.springframework.beans.factory.support.FactoryBeanRegistrySupport.doGetObjectFromFactoryBean(FactoryBeanRegistrySupport.java:178)
at org.springframework.beans.factory.support.FactoryBeanRegistrySupport.getObjectFromFactoryBean(FactoryBeanRegistrySupport.java:101)
at org.springframework.beans.factory.support.AbstractBeanFactory.getObjectForBeanInstance(AbstractBeanFactory.java:1674)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.getObjectForBeanInstance(AbstractAutowireCapableBeanFactory.java:1249)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:257)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199)
at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:277)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.addCandidateEntry(DefaultListableBeanFactory.java:1474)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.findAutowireCandidates(DefaultListableBeanFactory.java:1431)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1214)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1171)
at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:857)
at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:760)
... 73 common frames omitted
Thanks everyone for your help.
Edit :
Finally the answer of Murilo Prado resolved the issue.
I also edited the code of the feign client :
IdentityProviderFeignClient (feign client)
#AuthorizedFeignClient(name = "identityprovider")
public interface IdentityProviderFeignClient {
#GetMapping("/api/account-identifiers")
List<AccountIdentifier> getAllAccountIdentifiers(#QueryParam("search") String criteria,
Pageable pageable, #RequestParam("queryParams") MultiValueMap<String, String> queryParams);
}
Try this
public class FeignConfig {
#Autowired
private ObjectFactory<HttpMessageConverters> messageConverters;
#Bean
#ConditionalOnMissingBean
public Decoder feignDecoder() {
return new OptionalDecoder(new ResponseEntityDecoder(new SpringDecoder(this.messageConverters)));
}
#Bean
#ConditionalOnMissingBean
public Encoder feignEncoder() {
return new SpringFormEncoder(new SpringEncoder(messageConverters));
}
}

IntegrationFlow Exception Handling

I am trying to create a Flow for message as follow:
TCPinboundAdapter ----> Message Brocker(ActiveMQ)
Flow:
This flow is created in the following way
The message is received via TCP connection to TCP Adapter which may be client or server.
The message received to TCP adapter is send to JMS Adapter(ActiveMQ Broker).
The code is as follow:
#EventListener
public void handleTcpConnectionClientEvent(TcpConnectionFailedEvent event){
TcpNioClientConnectionFactory tcp = (TcpNioClientConnectionFactory)event.getSource();
System.out.println(tcp);
System.out.println("connection exception client :::"+event.getSource());
this.status = event.toString();
}
#EventListener
public void handleTcpConnectionServerExceptionEvent(TcpConnectionServerExceptionEvent event){
System.out.println("connection exception server :::");
this.status = event.toString();
}
// this method is invoked when the connection with the sever got disconnected
#EventListener
public void handleTcpConnectionServerEvent(TcpConnectionExceptionEvent event){
System.out.println("connection exception serversssss :::"+event.getConnectionFactoryName());
this.status = event.toString();
}
//when the connection got established (not for first time)
#EventListener
public void handleTcpConnectionCloseEvent(TcpConnectionOpenEvent event){
System.out.println("connection opened :::"+event.getConnectionFactoryName());
// status = event.toString();
}
// create a server connection and flow to JMS
private void createServerConnection(HostConnection hostConnection) throws Throwable{
this.status = "success";
// IntegrationFlow flow;
IntegrationFlowRegistration theFlow;
IntegrationFlow flow =
IntegrationFlows.from(Tcp.inboundAdapter(Tcp.netServer(1234)
.serializer(customSerializer)
.deserializer(customSerializer)
.id(hostConnection.getConnectionNumber()).soTimeout(10000)))
.enrichHeaders(f->f.header("abc","abc")))
.channel(directChannel())
.handle(Jms.outboundAdapter(ConnectionFactory())
.destination("jmsInbound"))
.get();
theFlow = this.flowContext.registration(flow).id("test.flow").register();
if(this.status.equals("success"))
createInboundFlow(hostConnection);
// startConnection(hostConnection.getConnectionNumber());
}
Issue:
This flow is created successfully and get registered to Application Context when there is no Exception.
But in case When there is an exception i.e (BindException)
When creating server to a particular port and the Port is already used
then it raise BindException then also the flow got registered
So, we want that the flow should not be registered when there is exception in any of the flow component below.
IntegrationFlowRegistration theFlow;
IntegrationFlow flow =
IntegrationFlows.from(Tcp.inboundAdapter(Tcp.netServer(1234)
.serializer(customSerializer)
.deserializer(customSerializer)
.id("server").soTimeout(10000)))
.enrichHeaders(f->f.header("abc","abc")))
.channel(directChannel())
.handle(Jms.outboundAdapter(ConnectionFactory())
.destination("jmsInbound"))
.get();
theFlow =this.flowContext.registration(flow).id("test.flow").register();
There are various Listener implemented to check exception in TCP connection try{}catch() block don't raise any exception.
Please provide a suitable approach to handle Exceptions for adapters currently I am using Listeners for various event to know there is something wrong with the tcp adapters.
After applying this approach provided by Mr. Artem Bilan
#EventListener
public void handleTcpConnectionServerExceptionEvent(TcpConnectionServerExceptionEvent event){
System.out.println("connection exception server :::"+event);
this.status = event.getCause().getMessage();
AbstractConnectionFactory server = (AbstractConnectionFactory)event.getSource();
System.out.println(server.getComponentName());
this.flowContext.remove(server.getComponentName()+"out.flow");
}
I am able to remove the flow using FlowId but I am not able to catch the Exception
The Exception below is printing on the console and can't be handled Even I have changed method to
private void createServerConnection(HostConnection hostConnection) throws Throwable{}
and handled these Exception with try{}catch(Throwable t){} in calling function
Exception in thread "pool-4-thread-1" java.lang.NullPointerException
Exception is described in more elaborated form in the logs provided below:
2018-05-17 21:01:40.850 INFO 18332 --- [nio-8080-exec-4]
.s.i.i.t.c.TcpNetServerConnectionFactory : started Co123, port=1234
2018-05-17 21:01:40.850 INFO 18332 --- [nio-8080-exec-4] o.s.i.ip.tcp.TcpReceivingChannelAdapter : started org.springframework.integration.ip.tcp.TcpReceivingChannelAdapter#3
2018-05-17 21:01:40.851 ERROR 18332 --- [pool-5-thread-1] .s.i.i.t.c.TcpNetServerConnectionFactory : Error on ServerSocket; port = 1234
java.net.BindException: Address already in use: JVM_Bind
at java.net.DualStackPlainSocketImpl.bind0(Native Method) ~[na:1.8.0_111]
at java.net.DualStackPlainSocketImpl.socketBind(Unknown Source) ~[na:1.8.0_111]
at java.net.AbstractPlainSocketImpl.bind(Unknown Source) ~[na:1.8.0_111]
at java.net.PlainSocketImpl.bind(Unknown Source) ~[na:1.8.0_111]
at java.net.ServerSocket.bind(Unknown Source) ~[na:1.8.0_111]
at java.net.ServerSocket.<init>(Unknown Source) ~[na:1.8.0_111]
at java.net.ServerSocket.<init>(Unknown Source) ~[na:1.8.0_111]
at javax.net.DefaultServerSocketFactory.createServerSocket(Unknown Source) ~[na:1.8.0_111]
at org.springframework.integration.ip.tcp.connection.TcpNetServerConnectionFactory.createServerSocket(TcpNetServerConnectionFactory.java:211) ~[spring-integration-ip-5.0.3.RELEASE.jar:5.0.3.RELEASE]
at org.springframework.integration.ip.tcp.connection.TcpNetServerConnectionFactory.run(TcpNetServerConnectionFactory.java:106) ~[spring-integration-ip-5.0.3.RELEASE.jar:5.0.3.RELEASE]
at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source) [na:1.8.0_111]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source) [na:1.8.0_111]
at java.lang.Thread.run(Unknown Source) [na:1.8.0_111]
connection exception server :::TcpConnectionServerExceptionEvent [source=Co123, port=1234, cause=java.net.BindException: Address already in use: JVM_Bind]
Co123
2018-05-17 21:01:40.851 INFO 18332 --- [pool-5-thread-1] o.s.i.ip.tcp.TcpReceivingChannelAdapter : stopped org.springframework.integration.ip.tcp.TcpReceivingChannelAdapter#3
2018-05-17 21:01:40.851 INFO 18332 --- [pool-5-thread-1] o.s.i.endpoint.EventDrivenConsumer : Removing {transformer} as a subscriber to the 'Co123out.flow.channel#0' channel
2018-05-17 21:01:40.852 INFO 18332 --- [pool-5-thread-1] o.s.integration.channel.DirectChannel : Channel 'application.Co123out.flow.channel#0' has 0 subscriber(s).
2018-05-17 21:01:40.852 INFO 18332 --- [pool-5-thread-1] o.s.i.endpoint.EventDrivenConsumer : stopped org.springframework.integration.config.ConsumerEndpointFactoryBean#11
2018-05-17 21:01:40.852 INFO 18332 --- [pool-5-thread-1] o.s.i.endpoint.EventDrivenConsumer : Removing {jms:outbound-channel-adapter} as a subscriber to the 'Co123out.flow.channel#1' channel
2018-05-17 21:01:40.852 INFO 18332 --- [pool-5-thread-1] o.s.integration.channel.DirectChannel : Channel 'application.Co123out.flow.channel#1' has 0 subscriber(s).
2018-05-17 21:01:40.852 INFO 18332 --- [pool-5-thread-1] o.s.i.endpoint.EventDrivenConsumer : stopped org.springframework.integration.config.ConsumerEndpointFactoryBean#12
Exception in thread "pool-4-thread-1" java.lang.NullPointerException
at org.springframework.integration.ip.tcp.connection.TcpNetServerConnectionFactory.run(TcpNetServerConnectionFactory.java:185)
at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
at java.lang.Thread.run(Unknown Source)
Exception in thread "pool-5-thread-1" java.lang.NullPointerException
at org.springframework.integration.ip.tcp.connection.TcpNetServerConnectionFactory.run(TcpNetServerConnectionFactory.java:185)
at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
at java.lang.Thread.run(Unknown Source)`
You register an IntegrationFlow via:
this.flowContext.registration(flow).id("test.flow").register();
The same his.flowContext bean and that id for the flow can be used to destroy the flow from any other place, e.g. an event listener, when you catch the mentioned BindException:
/**
* Destroy an {#link IntegrationFlow} bean (as well as all its dependant beans)
* for provided {#code flowId} and clean up all the local cache for it.
* #param flowId the bean name to destroy from
*/
void remove(String flowId);

Resources