Spring Boot replacing application property on startup - spring-boot

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.

Related

SpelEvaluationException when initiating GET on a SftpOutboundGateway

I have a Spring Integration Flow starting with a SFTPOutboundGateway. It should get a file from a SFTP server. The file contains Event objects in JSON format. My configuration is:
#Bean
public DirectChannelSpec sftpGetInputChannel() {
return MessageChannels.direct();
}
#Bean
public QueueChannelSpec remoteFileOutputChannel() {
return MessageChannels.queue();
}
#Bean(name = PollerMetadata.DEFAULT_POLLER)
public PollerMetadata defaultPoller() {
PollerMetadata pollerMetadata = new PollerMetadata();
pollerMetadata.setTrigger(new PeriodicTrigger(5000));
return pollerMetadata;
}
#Bean
public IntegrationFlow sftpGetFlow(TransferContext context) {
return IntegrationFlows.from("sftpGetInputChannel")
.handle(Sftp.outboundGateway(sftpSessionFactory(context.getChannel()),
AbstractRemoteFileOutboundGateway.Command.GET, "payload")
.remoteDirectoryExpression(context.getRemoteDir())
.localDirectory(new File(context.getLocalDir()))
.localFilenameExpression(context.getLocalFilename())
)
.channel("remoteFileOutputChannel")
.transform(Transformers.fromJson(Event[].class))
.get();
}
To get a file from the SFTP server I send a message to the gateway's input channel "sftpGetInputChannel":
boolean sent = sftpGetInputChannel.send(new GenericMessage<>(env.getRemoteDir() + "/" + env.getRemoteFilename()));
An SpelEvaluationException is thrown when trying to interprete the given filename. Both fields, remoteDir and remoteFilename are of type String:
org.springframework.messaging.MessageHandlingException: error occurred in message handler [bean 'sftpGetFlow.sftp:outbound-gateway#0' for component 'sftpGetFlow.org.springframework.integration.config.ConsumerEndpointFactoryBean#0'; defined in: 'class path resource [com/harry/potter/job/config/SftpConfiguration.class]'; from source: 'bean method sftpGetFlow']; nested exception is org.springframework.messaging.MessagingException: Failed to execute on session; nested exception is org.springframework.expression.spel.SpelEvaluationException: EL1001E: Type conversion problem, cannot convert from org.springframework.messaging.support.GenericMessage<?> to java.lang.String
at org.springframework.integration.support.utils.IntegrationUtils.wrapInHandlingExceptionIfNecessary(IntegrationUtils.java:192)
at org.springframework.integration.handler.AbstractMessageHandler.handleMessage(AbstractMessageHandler.java:79)
at org.springframework.integration.dispatcher.AbstractDispatcher.tryOptimizedDispatch(AbstractDispatcher.java:115)
at org.springframework.integration.dispatcher.UnicastingDispatcher.doDispatch(UnicastingDispatcher.java:133)
at org.springframework.integration.dispatcher.UnicastingDispatcher.dispatch(UnicastingDispatcher.java:106)
at org.springframework.integration.channel.AbstractSubscribableChannel.doSend(AbstractSubscribableChannel.java:72)
at org.springframework.integration.channel.AbstractMessageChannel.send(AbstractMessageChannel.java:570)
at org.springframework.integration.channel.AbstractMessageChannel.send(AbstractMessageChannel.java:520)
at com.harry.potter.job.MyTask.getFile(MyEventsTask.java:170)
at com.harry.potter.job.myTask.runAsTask(MyEventsTask.java:112)
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.springframework.scheduling.support.ScheduledMethodRunnable.run(ScheduledMethodRunnable.java:84)
at org.springframework.scheduling.support.DelegatingErrorHandlingRunnable.run(DelegatingErrorHandlingRunnable.java:54)
at org.springframework.scheduling.concurrent.ReschedulingRunnable.run(ReschedulingRunnable.java:93)
at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:515)
at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
at java.base/java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:304)
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:836)
Caused by: org.springframework.messaging.MessagingException: Failed to execute on session; nested exception is org.springframework.expression.spel.SpelEvaluationException: EL1001E: Type conversion problem, cannot convert from org.springframework.messaging.support.GenericMessage<?> to java.lang.String
at org.springframework.integration.file.remote.RemoteFileTemplate.execute(RemoteFileTemplate.java:448)
at org.springframework.integration.file.remote.gateway.AbstractRemoteFileOutboundGateway.doGet(AbstractRemoteFileOutboundGateway.java:680)
at org.springframework.integration.file.remote.gateway.AbstractRemoteFileOutboundGateway.handleRequestMessage(AbstractRemoteFileOutboundGateway.java:584)
at org.springframework.integration.handler.AbstractReplyProducingMessageHandler.handleMessageInternal(AbstractReplyProducingMessageHandler.java:134)
at org.springframework.integration.handler.AbstractMessageHandler.handleMessage(AbstractMessageHandler.java:62)
... 21 common frames omitted
Caused by: org.springframework.expression.spel.SpelEvaluationException: EL1001E: Type conversion problem, cannot convert from org.springframework.messaging.support.GenericMessage<?> to java.lang.String
at org.springframework.expression.spel.support.StandardTypeConverter.convertValue(StandardTypeConverter.java:75)
at org.springframework.expression.common.ExpressionUtils.convertTypedValue(ExpressionUtils.java:57)
at org.springframework.expression.spel.standard.SpelExpression.getValue(SpelExpression.java:377)
at org.springframework.integration.file.remote.gateway.AbstractRemoteFileOutboundGateway.generateLocalFileName(AbstractRemoteFileOutboundGateway.java:1316)
at org.springframework.integration.file.remote.gateway.AbstractRemoteFileOutboundGateway.get(AbstractRemoteFileOutboundGateway.java:1081)
at org.springframework.integration.file.remote.gateway.AbstractRemoteFileOutboundGateway.lambda$doGet$6(AbstractRemoteFileOutboundGateway.java:681)
at org.springframework.integration.file.remote.gateway.AbstractRemoteFileOutboundGateway$$Lambda$30183/0x0000000000000000.doInSession(Unknown Source)
at org.springframework.integration.file.remote.RemoteFileTemplate.execute(RemoteFileTemplate.java:439)
... 25 common frames omitted
Caused by: org.springframework.core.convert.ConverterNotFoundException: No converter found capable of converting from type [org.springframework.messaging.support.GenericMessage<?>] 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.expression.spel.support.StandardTypeConverter.convertValue(StandardTypeConverter.java:70)
... 32 common frames omitted
What do I wrong?
Okay, the problem is not within the message to get the file but in the configuration of the gateway:
.localFilenameExpression(context.getLocalFilename())
Just to set the local filename as expression is not allowed because dots - often part of the filename - is a SpEL delimiter to separate bean from method name. Hence the expression becomes invalid.
Possible expression would be:
.localFilenameExpression("#remoteFileName")
See its JavaDocs:
/**
* Specify a SpEL expression for local files renaming after downloading.
* #param localFilenameExpression the SpEL expression to use.
* #return the Spec.
*/
public S localFilenameExpression(String localFilenameExpression) {
And here is some code snippet how it works:
private String generateLocalFileName(Message<?> message, String remoteFileName) {
if (this.localFilenameGeneratorExpression != null) {
EvaluationContext evaluationContext = ExpressionUtils.createStandardEvaluationContext(getBeanFactory());
evaluationContext.setVariable("remoteFileName", remoteFileName);
return this.localFilenameGeneratorExpression.getValue(evaluationContext, message, String.class);
}
return remoteFileName;
}
The expression you can provide should somehow be in the context of the currently downloaded remote file. Not sure what is yours static context.getLocalFilename(). You can build a local file name based on the request message and that remoteFileName variable contexts.
See more in docs: https://docs.spring.io/spring-integration/docs/current/reference/html/sftp.html#configuring-with-the-java-dsl-3
The sample over there is like this:
.localDirectoryExpression("'myDir/' + #remoteDirectory")
.localFilenameExpression("#remoteFileName.replaceFirst('sftpSource', 'localTarget')"))

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);

EntityManager Bean creation exception only with ShadowJar, java.lang.IllegalArgumentException: Not a parameterized type. With Apache Beam libraries

I am getting the following error on entityManager bean creation, only when I am running a shadowJar.
bootJar or bootRun doesn't give any exception; it works fine. I need to create a shadow jar.
Exception
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'elabsEntityManager' defined in class path resource [com/sample/orchestrator/config/ElabsDataSourceConfig.class]: Invocation of init method failed; nested exception is java.lang.IllegalArgumentException: Not a parameterized type!
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1788)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:609)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:531)
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:335)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:333)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:208)
at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1159)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:913)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:588)
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:144)
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:767)
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:759)
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:426)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:326)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1311)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1300)
at com.sample.orchestrator.OrchestratorApplication.main(OrchestratorApplication.java:27)
Caused by: java.lang.IllegalArgumentException: Not a parameterized type!
at org.jboss.jandex.Type.asParameterizedType(Type.java:228)
at org.jboss.jandex.Indexer.resolveTypePath(Indexer.java:768)
at org.jboss.jandex.Indexer.resolveTypePath(Indexer.java:780)
at org.jboss.jandex.Indexer.resolveTypePath(Indexer.java:775)
at org.jboss.jandex.Indexer.resolveTypeAnnotation(Indexer.java:718)
at org.jboss.jandex.Indexer.resolveTypeAnnotations(Indexer.java:613)
at org.jboss.jandex.Indexer.index(Indexer.java:1602)
at org.hibernate.boot.archive.scan.spi.ClassFileArchiveEntryHandler.toClassDescriptor(ClassFileArchiveEntryHandler.java:64)
at org.hibernate.boot.archive.scan.spi.ClassFileArchiveEntryHandler.handleEntry(ClassFileArchiveEntryHandler.java:52)
at org.hibernate.boot.archive.internal.JarFileBasedArchiveDescriptor.visitArchive(JarFileBasedArchiveDescriptor.java:147)
at org.hibernate.boot.archive.scan.spi.AbstractScannerImpl.scan(AbstractScannerImpl.java:48)
at org.hibernate.boot.model.process.internal.ScanningCoordinator.coordinateScan(ScanningCoordinator.java:76)
at org.hibernate.boot.model.process.spi.MetadataBuildingProcess.prepare(MetadataBuildingProcess.java:107)
at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.<init>(EntityManagerFactoryBuilderImpl.java:254)
at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.<init>(EntityManagerFactoryBuilderImpl.java:168)
at org.springframework.orm.jpa.vendor.SpringHibernateJpaPersistenceProvider.createContainerEntityManagerFactory(SpringHibernateJpaPersistenceProvider.java:52)
at org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.createNativeEntityManagerFactory(LocalContainerEntityManagerFactoryBean.java:365)
at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.buildNativeEntityManagerFactory(AbstractEntityManagerFactoryBean.java:409)
at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.afterPropertiesSet(AbstractEntityManagerFactoryBean.java:396)
at org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.afterPropertiesSet(LocalContainerEntityManagerFactoryBean.java:341)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1847)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1784)
... 17 more
build.gradle
dependencies {
// Comment these beam libraries to not see the error in shadow jar But i need this
implementation 'org.apache.beam:beam-sdks-java-core:2.27.0'
implementation 'org.apache.beam:beam-runners-direct-java:2.27.0'
implementation 'org.apache.beam:beam-runners-google-cloud-dataflow-java:2.27.0'
// ....other dependencies
}
jar {
manifest {
attributes "Main-Class": "com.sample.orchestrator.OrchestratorApplication"
}
from {
configurations.compile.collect { it.isDirectory() ? it : zipTree(it) }
}
}
shadowJar {
zip64 = true
exclude "**/Log4j2Plugins.dat"
// Required for Spring
mergeServiceFiles()
append 'META-INF/spring.handlers'
append 'META-INF/spring.schemas'
append 'META-INF/spring.tooling'
transform(PropertiesFileTransformer) {
paths = ['META-INF/spring.factories' ]
mergeStrategy = "append"
}
}
Here is the entity manager related beans.
#Configuration
#EnableJpaRepositories(basePackages = {
"com.sample.orchestrator.database.elabs.repository" }, entityManagerFactoryRef = "elabsEntityManager", transactionManagerRef = "elabsTransactionManager")
#PropertySource("classpath:application-${spring.profiles.active}.yml")
public class ElabsDataSourceConfig {
#Value("${spring.datasource-elabs.driver-class-name}")
private String driverClassName;
#Value("${spring.datasource-elabs.url}")
private String url;
#Value("${spring.datasource-elabs.username}")
private String username;
#Value("${spring.datasource-elabs.password}")
private String password;
#Value("${spring.jpa.database-platform}")
private String dialect;
#Value("$(spring.jpa.hibernate.ddl-auto)")
private String ddlAuto;
#Value("$(spring.jpa.show-sql)")
private String showSql;
#Bean(name = "datasource-elabs")
public DataSource datasourceElabs() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName(driverClassName);
dataSource.setUrl(url);
dataSource.setUsername(username);
dataSource.setPassword(password);
return dataSource;
}
#Bean("elabsEntityManager")
public LocalContainerEntityManagerFactoryBean elabsEntityManager() {
LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
em.setDataSource(datasourceElabs());
HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
em.setJpaVendorAdapter(vendorAdapter);
em.setPackagesToScan(new String[] { "com.sample.orchestrator.model.database.elabs" });
// em.setPersistenceXmlLocation("classpath:persistence.xml");
HashMap<String, Object> properties = new HashMap<>();
properties.put("hibernate.dialect", dialect);
properties.put("hibernate.ddl-auto", ddlAuto);
properties.put("hibernate.show-sql", showSql);
em.setJpaPropertyMap(properties);
return em;
}
#Bean("elabsTransactionManager")
public PlatformTransactionManager elabsTransactionManager() {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(elabsEntityManager().getObject());
return transactionManager;
}
}
Here is a sample program.
To run please include
./gradlew bootRun -Pdev
./gradlew bootJar and include "-Dspring.profiles.active=dev" while running
./gradlew shadowJar and include "-Dspring.profiles.active=dev" -- Error Step.
The reason I am not using bootJar, because I am creating a google dataflow pipeline with the application, the dependent jar files aren't staged from bootJar(Beam needs absolute path of dependencies to stage the relevant files). But I have tried with a non spring maven shaded jar, all the dependent files were staged. Hoping to achieve the same with spring shadowJar.

can I use xml wire with java annotation in spring

I have a class of GenerateKey which is for spring mvc boot. Since it needs to contact database and message queue, so I tried to wire it using xml
#RestController
public class GenerateKey {
final private DriverManagerDataSource dataSource;
final private AmqpTemplate rabbitMQTemplate;
final private String queueName;
public GenerateKey(DriverManagerDataSource dataSource,AmqpTemplate rabbitMQTemplate,String queueName){
this.dataSource=dataSource;
this.rabbitMQTemplate =rabbitMQTemplate;
this.queueName =queueName;
}
#RequestMapping("/key/generate")
public String generateKey(#RequestParam(value = "businesskey") String businesskey, #RequestParam(value = "customer") String customer, Model model) {
JdbcTemplate jdbctemplate = new JdbcTemplate(dataSource);
JSONObject obj = new JSONObject();
obj.put("businesskey", businesskey);
obj.put("customer", customer);
rabbitMQTemplate.convertAndSend(queueName, obj.toString());
System.out.println(businesskey+customer);
return "greeting" + businesskey + customer;
}
}
the xml configurations is as the following and using
#ImportResource( { "rabbit-listener-context.xml" } )
to import it
<bean id="request" class="com.testcom.keyservice.GenerateKey" c:dataSource-ref="dataSource" c:rabbitMQTemplate-ref="keyRequestTemplate" c:queueName="${keyRequestQueueName}"/>
but it complain "No default constructor found" as following:
2014-11-26 21:42:16.095 INFO 17400 --- [ main] utoConfigurationReportLoggingInitializer :
Error starting ApplicationContext. To display the auto-configuration report enabled debug logging (start with --debug)
2014-11-26 21:42:16.097 ERROR 17400 --- [ main] o.s.boot.SpringApplication : Application startup failed
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'generateKey' defined in file [/home/oracle/NetBeansProjects/rabbitmq-native/keyService/build/classes/main/com/testcom/keyservice/GenerateKey.class]: Instantiation of bean failed; nested exception is org.springframework.beans.BeanInstantiationException: Could not instantiate bean class [com.testcom.keyservice.GenerateKey]: No default constructor found; nested exception is java.lang.NoSuchMethodException: com.testcom.keyservice.GenerateKey.<init>()
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateBean(AbstractAutowireCapableBeanFactory.java:1095)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1040)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:505)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:476)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:302)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:229)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:298)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:193)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:725)
Exception in thread "main" at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:762)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicatixt.java:482)
at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.refresh(EmbeddedWebApplicationContext.java:109)
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:691)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:320)
Since you are using Spring Boot I assume you have also #ComponentScan active in your application. Because of that you create two instances of GenerateKey class - once because of #RestController annotation, second time in XML. I believe that's not what you want to achieve.
Get rid of XML declaration of request bean representing GeneratorKey class and use only Java based autowiring.
#RestController
public class GenerateKey {
private final DriverManagerDataSource dataSource;
private final AmqpTemplate rabbitMQTemplate;
private final String queueName;
#Autowired
public GenerateKey(#Qualifier("dataSource") DriverManagerDataSource dataSource, #Qualifier("keyRequestTemplate") AmqpTemplate rabbitMQTemplate, #Value("${keyRequestQueueName}") String queueName) {
this.dataSource=dataSource;
this.rabbitMQTemplate =rabbitMQTemplate;
this.queueName =queueName;
}

Custom Liquibase Change error when integrating with Spring: Unknown Liquibase extension. Are you missing a jar from your classpath?

As part of the database upgrade for an existing application, a custom Liquibase change which extends AbstractChange has been created:
#DatabaseChange(name = "springBeanChange", description = "Runs a spring bean custom change", priority = ChangeMetaData.PRIORITY_DEFAULT)
public class SpringBeanChange extends AbstractChange {
private String beanName;
private String changeClass;
#DatabaseChangeProperty(description = "Spring bean name (optional)")
public String getBeanName() {
return this.beanName;
}
public void setBeanName(final String beanName) {
this.beanName = beanName;
}
#DatabaseChangeProperty(description = "Spring bean class")
public String getChangeClass() {
return this.changeClass;
}
public void setChangeClass(final String changeClass) {
this.changeClass = changeClass;
}
private CustomTaskChange bean;
#Override
public boolean generateStatementsVolatile(final Database database) {
return true;
}
#Override
public String getConfirmationMessage() {
return findBean().getConfirmationMessage();
}
#Override
public SqlStatement[] generateStatements(final Database database) {
try {
findBean().execute(database);
} catch (CustomChangeException e) {
throw new UnexpectedLiquibaseException(e);
}
return new SqlStatement[0];
}
#SuppressWarnings("unchecked")
private CustomTaskChange findBean() {
Class<CustomTaskChange> requiredType = CustomTaskChange.class;
if (this.changeClass != null) {
try {
Class<?> requestedType = Class.forName(this.changeClass);
if (CustomTaskChange.class.isAssignableFrom(requestedType)) {
requiredType = (Class<CustomTaskChange>) requestedType;
} else {
throw new UnexpectedLiquibaseException(
"Specified changeClass " + this.changeClass
+ " was not an instance of "
+ CustomTaskChange.class);
}
} catch (ClassNotFoundException e) {
throw new UnexpectedLiquibaseException(
"Could not create change class", e);
}
}
if (this.bean == null) {
if (getBeanName() == null) {
this.bean = SpringContextHolder.getInstance().getContext()
.getBean(requiredType);
} else {
this.bean = SpringContextHolder.getInstance().getContext()
.getBean(getBeanName(), requiredType);
}
}
return this.bean;
}
#Override
public ValidationErrors validate(final Database database) {
try {
return findBean().validate(database);
} catch (NullPointerException p_exception) {
return new ValidationErrors()
.addError("Exception thrown calling validate():"
+ p_exception.getMessage());
} catch (UnexpectedLiquibaseException p_exception) {
return new ValidationErrors()
.addError("Exception thrown calling validate():"
+ p_exception.getMessage());
} catch (NoSuchBeanDefinitionException p_exception) {
return new ValidationErrors()
.addError("Exception thrown calling validate():"
+ p_exception.getMessage());
} catch (BeanNotOfRequiredTypeException p_exception) {
return new ValidationErrors()
.addError("Exception thrown calling validate():"
+ p_exception.getMessage());
} catch (BeansException p_exception) {
return new ValidationErrors()
.addError("Exception thrown calling validate():"
+ p_exception.getMessage());
}
}
}
This is then configured in the database change log XML file as follows:
<changeSet id="15" author="theauthor">
<XXX:springBeanChange
changeClass="XXX.XXX.XXX.upgrade.tasks.TaskUpgrade" />
</changeSet>
Where TaskUpgrade implements CustomTaskChange and is the class that is returned get the call to getBean in SpringBeanChange.
The database change log file also contains many 'normal' liquibase commands such as addColumn.
A custom Java class has then been written which actually performs the upgrade (the following lines show the important lines of code which actually do the upgrade). This Java program is manually executed after the application has been deployed onto the server:
Liquibase liquibase =
new Liquibase(getChangeLogFile(), new ClassLoaderResourceAccessor(), new JdbcConnection(conn));
if ("update".equalsIgnoreCase(command)) {
liquibase.update(contexts);
} else {
throw new IllegalArgumentException("Unknown command " + command);
}
This works fine and executes the database upgrade.
I'm looking to avoid the need to use the custom Java program to perform the upgrade and actually do it when the application starts up. The app already uses Spring so it makes sense to to the upgrade when the Spring context is initialising.
To do this, I've added the following to the applicationContext file:
<bean id="myLiquibase" class="liquibase.integration.spring.SpringLiquibase">
<property name="dataSource" ref="dataSource" />
<property name="changeLog" value="classpath:databaseChangeLog.xml" />
<property name="contexts" value="test, production" />
</bean>
However, when the application starts up, I get the following exception:
2014-03-25 13:02:16,097 [main] ERROR context.ContextLoader - Context initialization failed
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'myLiquibase' defined in class path resource [applicationContext.xml]: Invocation of init method failed; nested exception is liquibase.exception.ChangeLogParseException: Invalid Migration File: Unknown Liquibase extension: springBeanChange. Are you missing a jar from your classpath?
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1488)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:524)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:461)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:295)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:223)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:292)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:194)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:626)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:932)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:479)
at org.springframework.web.context.ContextLoader.configureAndRefreshWebApplicationContext(ContextLoader.java:389)
at org.springframework.web.context.ContextLoader.initWebApplicationContext(ContextLoader.java:294)
at org.springframework.web.context.ContextLoaderListener.contextInitialized(ContextLoaderListener.java:112)
at org.mortbay.jetty.handler.ContextHandler.startContext(ContextHandler.java:549)
at org.mortbay.jetty.servlet.Context.startContext(Context.java:136)
at org.mortbay.jetty.webapp.WebAppContext.startContext(WebAppContext.java:1282)
at org.mortbay.jetty.handler.ContextHandler.doStart(ContextHandler.java:518)
at org.mortbay.jetty.webapp.WebAppContext.doStart(WebAppContext.java:499)
at org.mortbay.component.AbstractLifeCycle.start(AbstractLifeCycle.java:50)
at org.mortbay.jetty.handler.HandlerWrapper.doStart(HandlerWrapper.java:130)
at org.mortbay.jetty.Server.doStart(Server.java:224)
at org.mortbay.component.AbstractLifeCycle.start(AbstractLifeCycle.java:50)
at XXX.XXX.XXX.demo.YYYDemo.main(YYYDemo.java:47)
Caused by: liquibase.exception.ChangeLogParseException: Invalid Migration File: Unknown Liquibase extension: springBeanChange. Are you missing a jar from your classpath?
at liquibase.parser.core.xml.XMLChangeLogSAXParser.parse(XMLChangeLogSAXParser.java:133)
at liquibase.Liquibase.update(Liquibase.java:129)
at liquibase.integration.spring.SpringLiquibase.performUpdate(SpringLiquibase.java:291)
at liquibase.integration.spring.SpringLiquibase.afterPropertiesSet(SpringLiquibase.java:258)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1547)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1485)
... 22 more
Caused by: org.xml.sax.SAXException: Unknown Liquibase extension: springBeanChange. Are you missing a jar from your classpath?
at liquibase.parser.core.xml.XMLChangeLogSAXHandler.startElement(XMLChangeLogSAXHandler.java:495)
at org.apache.xerces.parsers.AbstractSAXParser.startElement(Unknown Source)
at org.apache.xerces.parsers.AbstractXMLDocumentParser.emptyElement(Unknown Source)
at org.apache.xerces.impl.xs.XMLSchemaValidator.emptyElement(Unknown Source)
at org.apache.xerces.impl.XMLNSDocumentScannerImpl.scanStartElement(Unknown Source)
at org.apache.xerces.impl.XMLDocumentFragmentScannerImpl$FragmentContentDispatcher.dispatch(Unknown Source)
at org.apache.xerces.impl.XMLDocumentFragmentScannerImpl.scanDocument(Unknown Source)
at org.apache.xerces.parsers.XML11Configuration.parse(Unknown Source)
at org.apache.xerces.parsers.XML11Configuration.parse(Unknown Source)
at org.apache.xerces.parsers.XMLParser.parse(Unknown Source)
at org.apache.xerces.parsers.AbstractSAXParser.parse(Unknown Source)
at org.apache.xerces.jaxp.SAXParserImpl$JAXPSAXParser.parse(Unknown Source)
at liquibase.parser.core.xml.XMLChangeLogSAXParser.parse(XMLChangeLogSAXParser.java:99)
... 27 more
Caused by: org.xml.sax.SAXException: Unknown Liquibase extension: springBeanChange. Are you missing a jar from your classpath?
at liquibase.parser.core.xml.XMLChangeLogSAXHandler.startElement(XMLChangeLogSAXHandler.java:359)
... 39 more
I can't find anything on the Liquibase site or anywhere else which provides any help as to what JAR I'm missing (if indeed I am missing one) or if anything else is missing/not defined.
Does anyone have any ideas?
Thanks in advance.
The jar that contains the custom extension is what is missing from your classpath. I don't use Spring, so I don't know how it sets up the classpath, but you probably need to either put the jar in a standard location so Spring can find it or else configure the Spring classpath.

Resources