jpa with https request multithreading spring - spring

I'm working with spring JPA and HTTP post request, fetching the data row by row then post the data into HTTP request to API and its worked fine with me, but here im working with bulk number of data, so i have to use multi-threading but im new with java and spring how do I implement to work with 10 thread and each one of them reads 1k per each time in parallel that here ?
i have read something about multithreading for 10 threads each thread of them read 1k row per each time, I have around 10 million records in my database
AccessingDataJpaApplication class :
#SpringBootApplication
public class AccessingDataJpaApplication implements CommandLineRunner {
private static final Logger logger = LoggerFactory.getLogger(AccessingDataJpaApplication.class);
#Autowired
private Bulk_repositoryRepository bulk_repositoryRepository;
public static void main(String[] args) {
SpringApplication.run(AccessingDataJpaApplication.class);
}
Date currentDate = new Date();
#Override
public void run(String... args) throws Exception {
RestTemplate restTemplate = new RestTemplate();
HttpHeaders headers = new HttpHeaders();
headers.setAccept(Arrays.asList(MediaType.APPLICATION_JSON));
headers.setBasicAuth("user", "pass");
while(true) {
Date currentDate = new Date();
logger.info("Just Started");
for (Bulk_repository churnss : bulk_repositoryRepository.findAllByStatusAndCampTypeAndCampStartDateLessThanEqualAndCampEndDateGreaterThanEqual(0,2,currentDate,currentDate)) {
System.out.print(churnss);
logger.info(churnss.toString());
AddOfferRequest AddOffer = new AddOfferRequest("113", churnss.getMsisdn(),churnss.getParam1());
logger.info(AddOffer.toString());
HttpEntity<AddOfferRequest> entity = new HttpEntity<AddOfferRequest>(AddOffer,headers);
ResponseEntity<String> responseEntity = restTemplate.exchange(
"api link", HttpMethod.POST, entity, String.class);
if(responseEntity.getStatusCode() == HttpStatus.OK){
String response = responseEntity.getBody();
churnss.setStatus(1);
churnss.setProcessDate(new Date());
churnss.setFulfilment_status(response);
logger.info(churnss.toString() + ", Response: " + response);
bulk_repositoryRepository.save(churnss);
}else {
logger.warn("Record Id: " + churnss.getId() + ", Http Failed Response: " + responseEntity.getStatusCode());
}
}
Thread.sleep(1000);
}
}
}
Bulk_repository class:
#Entity
#Table(name = "BULK_REPOSITORY")
public class Bulk_repository {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
#Column(name = "id")
private long id;
#Column(name = "msisdn")
private String msisdn;
#Column(name = "camp_start_date")
private Date campStartDate;
#Column(name = "camp_end_date")
private Date campEndDate;
#Column(name = "camp_type")
private int campType;
#Column(name = "camp_cd")
private String camp_cd;
#Column(name = "status")
private int status;
#Column(name = "process_date")
private Date processDate;
#Column(name = "entry_date")
private Date entryDate;
#Column(name = "entry_user")
private String entry_user;
#Column(name = "param1")
private String param1;
#Column(name = "param2")
private String param2;
#Column(name = "param3")
private String param3;
#Column(name = "param4")
private String param4;
#Column(name = "param5")
private String param5;
#Column(name = "error_desc")
private String error_desc;
#Column(name = "fulfilment_status")
private int fulfilment_status;
##then getter and setters and tostring
Bulk_repositoryRepository class :
public interface Bulk_repositoryRepository extends CrudRepository<Bulk_repository, Long> {
Date today = new Date();
List<Bulk_repository>findAllByStatusAndCampTypeAndCampStartDateLessThanEqualAndCampEndDateGreaterThanEqual(int status, int campType,Date today0, Date today1);
Bulk_repository findById(long id);
}
AddOfferRequest class :
public class AddOfferRequest {
private String ChannelID="113";
private String MSISDN;
private String ServiceID;
public AddOfferRequest() {
}
public AddOfferRequest(String channelID,String mSISDN,String serviceID ) {
this.MSISDN = mSISDN;
this.ServiceID = serviceID;
}
## then getter and setter and tostring
i have created AsyncConfiguration class:
package com.example.accessingdatajpa;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import java.util.concurrent.Executor;
#Configuration
#EnableAsync
public class AsyncConfiguration {
private static final Logger LOGGER = LoggerFactory.getLogger(AsyncConfiguration.class);
#Bean (name = "taskExecutor")
public Executor taskExecutor() {
LOGGER.debug("Creating Async Task Executor");
final ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(2);
executor.setMaxPoolSize(2);
executor.setQueueCapacity(1000);
executor.setThreadNamePrefix("CarThread-");
executor.initialize();
return executor;
}
}
but till now i can't undertand how can combaine the findby and http post with multithreading

Rewrite your code. Instead of a List<Bulk_repository> return a Stream<Bulk_repository>. This will lazily load the records from the database, instead of trying to do everything at once.
Then use the TaskExecutor to execute the different requests per thread, just give a task to it and it will be executed when there is a free thread.
#SpringBootApplication
public class AccessingDataJpaApplication implements CommandLineRunner {
private static final Logger logger = LoggerFactory.getLogger(AccessingDataJpaApplication.class);
#Autowired
private Bulk_repositoryRepository bulk_repositoryRepository;
#Autowired
private AsyncTaskExecutor executor;
#Autowired
private RestTemplate rest;
public static void main(String[] args) {
SpringApplication.run(AccessingDataJpaApplication.class);
}
#Override
public void run(String... args) throws Exception {
Date currentDate = new Date();
Stream< Bulk_repository> results = Bulk_repository churnss : bulk_repositoryRepository.findAllByStatusAndCampTypeAndCampStartDateLessThanEqualAndCampEndDateGreaterThanEqual(0,2,currentDate,currentDate);
results.forEach(it -> executor.submit(this.process(it)));
Thread.sleep(1000);
}
private void process(RestTemplate rest, Bulk_repository churnss) {
AddOfferRequest AddOffer = new AddOfferRequest("113", churnss.getMsisdn(),churnss.getParam1());
HttpEntity<AddOfferRequest> entity = new HttpEntity<AddOfferRequest>(AddOffer,headers);
try {
ResponseEntity<String> responseEntity = restTemplate.exchange(
"api link", HttpMethod.POST, entity, String.class);
if(responseEntity.getStatusCode() == HttpStatus.OK){
String response = responseEntity.getBody();
churnss.setStatus(1);
churnss.setProcessDate(new Date());
churnss.setFulfilment_status(response);
bulk_repositoryRepository.save(churnss);
}else {
logger.warn("Record Id: {}, Http Failed Response: {}",churnss.getId(), responseEntity.getStatusCode());
}
} catch (RestClientException rce) {
logger.warn("Record Id: {} Http Failed. ", churnss.getId(), rce);
}
}
}
NOTE: This was typed from the top of my head and isn't tested. However should provide some guidance.

Using #Async annotations to implement mutithread in spring. It can help you.
https://spring.io/guides/gs/async-method/
https://docs.spring.io/spring-data/rest/docs/2.0.0.M1/reference/html/paging-chapter.html

Try with Batch Insert/Update with Hibernate/JPA. Here is a nice tutorial
spring.jpa.properties.hibernate.jdbc.batch_size=500

Related

Spring boot JPARepository doesn't execute save

Im building a simple app in spring boot and having problems with saving an entity to the db. The bank account is saved normally, but the transaction is not being saved.
The weird thing is that there are no errors or anything. On the first transactionRepository call the method is exited and the app continues normally. I don't get any message in the console or and didn't find any problems using debugging.
Here is the makeTransaction() method, which executes normally until transactionRepository.save(...)
public void makeTransaction(Iban sourceIban, Iban destinationIban, double amount)
throws Exception {
BankAccountEntity sourceAccount = getBankAccountByIban(sourceIban);
BankAccountEntity destinationAccount = getBankAccountByIban(destinationIban);
Date currentDate = new Date();
TransactionEntity sourceTransaction = new TransactionEntity(sourceAccount, sourceIban, destinationIban, currentDate, amount);
TransactionEntity destinationTransaction = new TransactionEntity(destinationAccount, sourceIban, destinationIban, currentDate, amount);
if (sourceAccount.getAmountDeductible() < amount || amount < 0) { // TODO amount checker
throw new Exception(ILLEGAL_TRANSACTION_AMOUNT_TEXT); // TODO change exception type
}
sourceAccount.reduceBalance(amount);
sourceAccount.addTransaction(sourceTransaction);
destinationAccount.increaseBalance(amount);
destinationAccount.addTransaction(destinationTransaction);
bankAccountRepository.save(sourceAccount);
bankAccountRepository.save(destinationAccount);
transactionRepository.save(sourceTransaction);
transactionRepository.saveAndFlush(destinationTransaction);
}
The class has the repositories initialized as follows
private final BankAccountRepository bankAccountRepository;
private final TransactionRepository transactionRepository;
public BankAccountService(#Autowired BankAccountRepository bankAccountRepository,
#Autowired TransactionRepository transactionRepository) {
this.bankAccountRepository = bankAccountRepository;
this.transactionRepository = transactionRepository;
}
The BankAccountRepository looks like this
public interface BankAccountRepository extends JpaRepository<BankAccountEntity, UUID> {
Optional<BankAccountEntity> findByIban(String iban);
}
And the TransactionRepository like this
public interface TransactionRepository extends JpaRepository<TransactionEntity, UUID> {}
The TransactionEntity looks like this
#Entity
#Table(name = "transactions")
public class TransactionEntity {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "transaction_id", nullable = false)
#Type(type = "uuid-char")
private Long transactionId;
private String sourceIban;
private String destinationIban;
private long dateExecuted;
private double amount;
#ManyToOne
#JoinColumn(name = "bank_account_id")
private BankAccountEntity bankAccount;
public TransactionEntity() {
}
public TransactionEntity(BankAccountEntity bankAccount, Iban sourceIban, Iban destinationIban, Date dateExecuted, double amount) {
this.bankAccount = bankAccount;
this.sourceIban = sourceIban.toString();
this.destinationIban = destinationIban.toString();
this.amount = amount;
this.dateExecuted = dateExecuted.getTime();
}
public BankAccountEntity getBankAccount() {
return bankAccount;
}
public void setBankAccount(BankAccountEntity bankAccount) {
this.bankAccount = bankAccount;
}
public Long getTransactionId() {
return transactionId;
}
public void setTransactionId(Long transactionId) {
this.transactionId = transactionId;
}
}

JPA: How to select a binary(16) UUID by a String UUID?

I have the following Entity:
#Data
#Entity
public class Comment implements Serializable {
#Id
#GeneratedValue(generator = "uuid4")
#GenericGenerator(name = "UUID", strategy = "uuid4")
#Column(columnDefinition = "BINARY(16)")
private UUID id;
#Column(columnDefinition = "BINARY(16)")
private UUID imageId;
private Instant creationTime;
private String text;
}
And a CRUD repo:
public interface CommentsRepository extends CrudRepository<Comment, UUID> {
List<Comment> findAllByImageId(final UUID imageId);
}
I add some example data:
#Component
#Slf4j
public class CommentsSampleData implements CommandLineRunner {
private final CommentsRepository repository;
#Autowired
public CommentsSampleData(final CommentsRepository repository) {
this.repository = repository;
}
#Override
public void run(String... args) {
createComment("617220ff-1642-4490-b589-869e7978c5e0", Instant.now(), "comment1");
createComment("617220ff-1642-4490-b589-869e7978c5e0", Instant.now(), "comment2");
createComment("617220ff-1642-4490-b589-869e7978c5e0", Instant.now(), "comment3");
createComment("e3a8aa57-6937-4f9e-b117-78bafe61b718", Instant.now(), "comment1");
}
private void createComment(
final String imageId,
final Instant creationTime,
final String text) {
final Comment comment = new Comment();
comment.setImageId(UUID.fromString(imageId));
comment.setCreationTime(creationTime);
comment.setText(text);
log.info("save comment: {}", comment);
repository.save(comment);
}
}
So the data in my table looks like the following:
So what is the best way now to select by those binary UUID's?
I will get string UUID's from the frontend So I guess I somehow need to convert those Strings to Binaryies. Whats the best way to do so so that it also works with ids and primary keys.
Example endpoint:
#Slf4j
#RestController
public class CommentsController {
private final CommentsService service;
public CommentsController(final CommentsService service) {
this.service = service;
}
#GetMapping(value = "/comments", produces = MediaType.APPLICATION_JSON_VALUE)
public List<Comment> getComments(#RequestParam("imageId") final UUID imageId) {
log.info("get comments by imageId: {}", imageId);
String existingIds = service.findAll().stream()
.map(Comment::getImageId)
.map(UUID::toString)
.collect(Collectors.joining(","));
log.info("Image Id Passed: {}", imageId);
log.info("Existing image ids: {}", existingIds);
String resultIds = service.findAllByImageId(imageId).stream()
.map(Comment::getImageId)
.map(UUID::toString)
.collect(Collectors.joining(","));
log.info("Result image ids: {}", resultIds);
return service.findAllByImageId(imageId);
}
}
When I now do a request:
localhost:8080/comments?imageId=617220ff-1642-4490-b589-869e7978c5e0
I get no result even though the UUID exists but not as string, it exists as binary(16) in the database:
d.f.a.c.service.CommentsController : Image Id Passed: 617220ff-1642-4490-b589-869e7978c5e0
d.f.a.c.service.CommentsController : Existing image ids: 617220ff-1642-4490-b589-869e7978c5e0,617220ff-1642-4490-b589-869e7978c5e0,617220ff-1642-4490-b589-869e7978c5e0,e3a8aa57-6937-4f9e-b117-78bafe61b718
d.f.a.c.service.CommentsController : Result image ids:
It is working as expected without any issue and it is auto converted between UUID and binary.
I recommend trying the following to make sure that id genuinely exists in database.
#GetMapping(value = "/comments", produces = MediaType.APPLICATION_JSON_VALUE)
public Iterable<Comment> getComments(#RequestParam("imageId")
final UUID imageId) {
log.info("get comments by imageId: {}", imageId);
String existingIds = service.findAll()
.map(Comment::getImageId)
.map(UUID::toString)
.collect(Collectors.joining(","));
log.info("Image Id Passed : {}", imageId);
log.info("Existing image ids : {}", existingIds);
return service.findAllByImageId(imageId);
}

Unable to insert rows in database using Spring Batch + Spring data

I am working with legacy database in which db tables has no keys. For java Sake i have to used Id annotation. My goal is to read data from .dat file and insert it into table. I'm using spring batch for the above said purpose. To improve the performance threading is used. But i'm getting insertion/updation issue that i'm unable to figure out. I have referenced many sources but none seems to solve my purpose. Kindly help me out by giving some appropriate solution or reference. Thanks in advance...
Entity.java
#Entity
#Table(name = "int_repl_mkt_val")
public class IntReplMktVal implements Serializable {
private static final long serialVersionUID = 1L;
#EmbeddedId
private IntReplMktValId id;
#Column(name = "acct_sys_cd")
private String acctSysCd;
#Column(name = "co_num", nullable = false)
private Integer coNum;
#Column(name = "last_mod_tmstmp")
#Temporal(TemporalType.TIMESTAMP)
private Date lastModTmstmp;
#Column(name = "pim_owned", nullable = false)
private String pimOwned;
#Column(name = "position", nullable = false)
private BigDecimal position;
#Column(name = "pricing_plan")
private String pricingPlan;
#Column(name="source_system",nullable=false)
private String sourceSystem;
... getter and setter
}
EmbeddedClass.java
#Embeddable
public class IntReplMktValId implements Serializable
{
private static final long serialVersionUID = 4824041485763129937L;
#Column(name = "acct_id",nullable=false)
private Integer acctId;
#Column(name = "asset_id",nullable=false)
private Integer assetId;
... getter and setter
}
jpaRepository.class
#Repository
public interface IntReplMktValRepository extends JpaRepository<IntReplMktVal, IntReplMktValId>
{
}
BatchConfiguration.class
#Configuration
public class IMAPPositionBatchConfiguration
{
#Autowired
JobBuilderFactory jobBuilderFactory;
#Autowired
StepBuilderFactory stepBuilderFactory;
#StepScope
#Bean(name="imapPositionReader")
public FlatFileItemReader<IMAPPositionInputMapperDTO> reader(#Value("#{jobParameters['fileName']}") String fileName) throws IOException
{
FlatFileItemReader<IMAPPositionInputMapperDTO> newBean = new FlatFileItemReader<>();
newBean.setName("fileReader");
newBean.setResource(new InputStreamResource(FileUtils.openInputStream(new File(fileName))));
newBean.setLineMapper(this.lineMapper());
newBean.setLinesToSkip(1);
return newBean;
}
public DefaultLineMapper<IMAPPositionInputMapperDTO> lineMapper()
{
DefaultLineMapper<IMAPPositionInputMapperDTO> lineMapper = new DefaultLineMapper<>();
lineMapper.setLineTokenizer(this.lineTokenizer());
IMAPPositionReader imapPositionReader = new IMAPPositionReader();
lineMapper.setFieldSetMapper(imapPositionReader);
return lineMapper;
}
public DelimitedLineTokenizer lineTokenizer()
{
DelimitedLineTokenizer tokenizer = new DelimitedLineTokenizer();
tokenizer.setDelimiter("|");
tokenizer.setNames("field1","field2","field3");
tokenizer.setIncludedFields(5,4,7);
return tokenizer;
}
public ItemProcessor<IMAPPositionInputMapperDTO, IntReplMktVal> processor()
{
return new IMAPPositionProcessor();
}
#Bean(name="imapPositionBatchWriter")
public ItemWriter<IntReplMktVal> writer()
{
return new IMAPPositionWriter();
}
#Bean(name="imapPositionListener")
public JobExecutionListenerSupport jobCompletionListener()
{
return new IMAPPositionJobListener();
}
#Bean(name="imapPositionTaskExecutor")
public ThreadPoolTaskExecutor taskExecutor()
{
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(50);
executor.setMaxPoolSize(100);
return executor;
}
#Bean(name="imapPositionStep")
public Step step(#Autowired #Qualifier("imapPositionTaskExecutor")TaskExecutor taskExecutor) throws IOException
{
return stepBuilderFactory.get("imapPositionStep")
.<IMAPPositionInputMapperDTO, IntReplMktVal>chunk(100)
.reader(this.reader(null))
.processor(this.processor())
.writer(this.writer())
.taskExecutor(taskExecutor)
.build();
}
#Bean(name="imapPositionFileImportJob")
public Job importUserJob(#Autowired #Qualifier("imapPositionStep") Step step)
{
return jobBuilderFactory
.get("imapPositionFileImportJob"+new Date())
.incrementer(new RunIdIncrementer())
.listener(this.jobCompletionListener())
.flow(step)
.end()
.build();
}
}
BatchWriter.java
public class IMAPPositionWriter implements ItemWriter<IntReplMktVal>
{
#Autowired
IntReplMktValRepository intReplMktValRepository;
#Override
public void write(List<? extends IntReplMktVal> items) throws Exception
{
intReplMktValRepository.saveAll(items);
}
}
ErrorLog
2019-06-07 17:22:01,522 ERROR [scopedTarget.imapPositionTaskExecutor-4] org.hibernate.internal.ExceptionMapperStandardImpl : HHH000346: Error during managed flush [org.hibernate.HibernateException: Duplicate identifier in table for: [com.capgroup.horizon.pricecapture.entities.IntReplMktVal#component[acctId,assetId]{assetId=274800, acctId=1}]]
NOTE: I have to insert all the data into table regardless of duplication or any other issue as keys are not defined so every data is valid.
Actually the problem was due to duplication found in persistent context which was resolved by setting the chunk size to 1.

Spring Repository - getting NullPointerException

I'm trying to save an object with Spring Data JPA. Unfortunately I always get a NullPointerException, and I don't understand why.
I followed this tutorial: https://www.callicoder.com/spring-boot-jpa-hibernate-postgresql-restful-crud-api-example/
I don't need a CRUD API so I left out the things that belong to it.
I get the following error:
java.lang.NullPointerException
at com.niclas.elitedangerousapi.handler.SystemPopulatedHandler.insertIntoDB(SystemPopulatedHandler.java:39)
at com.niclas.elitedangerousapi.Main.main(Main.java:19)
[main] ERROR c.n.e.h.SystemPopulatedHandler - null
UPDATE
I want to fill my database, but then when I want. At the end it should be so that every night a file is downloaded and then stored in the Database. Later I want to make the data accessible via an API.I want to execute this method (systemPopulatedHandler.insertIntoDB()) at the start and every x hours.
SystemPopulated.class
#Data
#Entity
#Table(name = "systems_populated")
#JsonIgnoreProperties(ignoreUnknown = true)
public class SystemPopulated {
#Id
#Column(name = "id")
private int id;
#Column(name = "edsm_id")
private long edsm_id;
#Column(name = "name")
private String name;
#Column(name = "x")
private double x;
#Column(name = "y")
private double y;
#Column(name = "z")
private double z;
#Column(name = "population")
private long population;
#Column(name = "is_populated")
private boolean is_populated;
#Column(name = "government_id")
private long government_id;
#Column(name = "government")
private String government;
#Column(name = "allegiance_id")
private int allegiance_id;
#Column(name = "allegiance")
private String allegiance;
#Column(name = "security_id")
private int security_id;
#Column(name = "security")
private String security;
#Column(name = "primary_economy_id")
private int primary_economy_id;
#Column(name = "primary_economy")
private String primary_economy;
#Column(name = "power")
private String power;
#Column(name = "power_state")
private String power_state;
#Column(name = "power_state_id")
private int power_state_id;
#Column(name = "needs_permit")
private boolean needs_permit;
#Column(name = "updated_at")
private long updated_at;
#Column(name = "controlling_minor_faction_id")
private int controlling_minor_faction_id;
#Column(name = "controlling_minor_faction")
private String controlling_minor_faction;
#Column(name = "reserve_type_id")
private int reserve_type_id;
#Column(name = "reserve_type")
private String reserve_type;
}
My SystemPopulatedRepository.class
#Repository
public interface SystemPopulatedRepository extends JpaRepository<SystemPopulated, Integer> {
}
My Class where i want to InsertIntoDB SystemPopulatedHandler.class
#Slf4j
public class SystemPopulatedHandler {
#Autowired
private SystemPopulatedRepository systemPopulatedRepository;
public void insertIntoDB() {
BufferedReader reader;
try {
reader = new BufferedReader( new FileReader(DOWNLOAD_SAVE_PATH + FILE_NAME_SYSTEMS_POPULATED) );
String line = reader.readLine();
while( line != null ){
ObjectMapper mapper = new ObjectMapper();
systemPopulatedRepository.save( mapper.readValue( line, SystemPopulated.class ) );
line = reader.readLine();
}
reader.close();
}
catch( Exception e ) {
e.printStackTrace();
log.error( e.getLocalizedMessage() );
}
}
}
My Main.class
#SpringBootApplication
#EnableJpaRepositories
public class Main {
public static void main( String[] args ) {
SpringApplication.run( Main.class, args );
SystemPopulatedHandler systemPopulatedHandler = new SystemPopulatedHandler();
systemPopulatedHandler.insertIntoDB();
}
}
The problem is that you create SystemPopulatedHandler yourself with
SystemPopulatedHandler systemPopulatedHandler = new SystemPopulatedHandler();
That way spring isn't injecting the repository into your class because that works only if spring creates the class.
But if you want to populate a database at startup (at least it seems that you try to do that) you should check out flyway (or 85.5 in this documentation: https://docs.spring.io/spring-boot/docs/current/reference/html/howto-database-initialization.html)
If you can't use flyway for some reason you can add the following code to the main class:
#Bean
public SystemPopulatedHandler systemPopulatedHandler(SystemPopulatedRepository repository) {
SystemPopulatedHandler systemPopulatedHandler = new SystemPopulatedHandler(repository);
systemPopulatedHandler.insertIntoDB()
return systemPopulatedHandler;
}
Afterwards add the constructor to the SystemPopulatedHandler class:
public SystemPopulatedHandler(SystemPopulatedRepository systemPopulatedRepository) {
this.systemPopulatedRepository = systemPopulatedRepository;
}
and remove the #Autowired annotation.
update
You also need to add the missing annotations as mentioned by this answer: https://stackoverflow.com/a/55767393/2248239
update 2
If you want to do that action periodically you can use scheduling (like in this guide https://spring.io/guides/gs/scheduling-tasks/)
Actually that's pretty easy:
Don't do the changes I mentioned above except adding the missing annotations and just do the following:
Add #Component to SystemPopulatedHandler
Add #Scheduled to insertIntoDB() in SystemPopulatedHandler
And add #EnableScheduling to the main class
For #Scheduled just read the guide it describes what you can do with the annotation.
This is due to the repository you have auto wired is not wiring the bean.
Please annonate your repository with #Repository
And in main class specify #EnableJpaRepository.
See the spring data JPA docs for more details
The problem is that you are instantiating the SystemPopulatedHandler bean without using ApplicationContext or BeanFactory, So it's not maintained by IOC container.
To use DI in a SpringBoot application all you need is to just auto wire SystemPopulatedHandler in your controller or service and then you can call insertIntoDB() method.
Since you are using spring boot and example is so simple you needn't make separate Configuration for beans.
#Controller
public class SystemPopulatedController {
#Autowired
private SystemPopulatedHandler systemPopulatedHandler;
#RequestMapping("/")
public void insertIntoDB() {
systemPopulatedHandler.insertIntoDB();
}
}
Many thanks to all of you. I have solved the problem as follows:
SystemPopulatedRepository.class
#Repository
public interface SystemPopulatedRepository extends JpaRepository<SystemPopulated, Integer> {
}
´´´
SystemPopulatedHandler.class
#Slf4j
#Component
public class SystemPopulatedHandler {
#Autowired
private SystemPopulatedRepository systemPopulatedRepository;
#PostConstruct
#Scheduled(cron = "0 0 0 * * *")
public void insertIntoDB() {
BufferedReader reader;
try {
reader = new BufferedReader( new FileReader(DOWNLOAD_SAVE_PATH + FILE_NAME_SYSTEMS_POPULATED) );
String line = reader.readLine();
while( line != null ){
ObjectMapper mapper = new ObjectMapper();
systemPopulatedRepository.save( mapper.readValue( line, SystemPopulated.class ) );
line = reader.readLine();
}
reader.close();
}
catch( Exception e ) {
e.printStackTrace();
log.error( e.getLocalizedMessage() );
}
}
}
´´´
Main.class
#SpringBootApplication
#EnableJpaRepositories
#EnableScheduling
public class Main {
public static void main( String[] args ) {
SpringApplication.run( Main.class, args );
FileHandler fileHandler = new FileHandler();
}
}

restTemplate returns "Count not extract response" exception

I have following code to consume a REST webservice and convert the results;however, when I run the code it returns following exception, I am also not sure how to handle other type of responses for example if a response with error code in its body is returned. I have found this questions 1 and 2 with similar topics but did not find much there.
Exception
org.springframework.web.client.RestClientException: Could not extract response: no suitable HttpMessageConverter found for response type [class com.project.web.FlightsResults] and content type [application/xml]
at org.springframework.web.client.HttpMessageConverterExtractor.extractData(HttpMessageConverterExtractor.java:110)
at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:576)
at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:537)
at org.springframework.web.client.RestTemplate.getForObject(RestTemplate.java:244)
at com.project.web.ArticleController.showArticles(ArticleController.java:36)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
....
The rest template code is as following:
RestTemplate restTemplate = new RestTemplate();
Map<String, String> vars = new HashMap<String, String>();
vars.put("user", "username");
vars.put("key", "password");
vars.put("fl", "po");
AvailabilityResponse flightResults = restTemplate
.getForObject(
"http://example.com/availabilityRequest?user={user}&key={key}&fl_type={fl}",
AvailabilityResponse.class, vars);
System.err.println(">>"
+ flightResults.getFlightList().get(0).getFlightOptions()
.getFlightOption().size());
XMLElements
#XmlRootElement(name = "availabilityResponse")
#XmlAccessorType(XmlAccessType.FIELD)
public class AvailabilityResponse {
#XmlElement(name = "flightList")
private List<FlightList> flightList;
public AvailabilityResponse() {
this.flightList = new ArrayList();
}
public List<FlightList> getFlightList() {
return flightList;
}
public void setFlightList(List<FlightList> flightList) {
this.flightList = flightList;
}
}
#XmlRootElement(name = "flightList")
#XmlAccessorType(XmlAccessType.FIELD)
public class FlightList {
#XmlElement(name = "flightOptions")
private FlightOptions flightOptions;
public FlightOptions getFlightOptions() {
return flightOptions;
}
public void setFlightOptions(FlightOptions flightOptions) {
this.flightOptions = flightOptions;
}
}
#XmlRootElement(name = "flightOptions")
#XmlAccessorType(XmlAccessType.FIELD)
public class FlightOptions {
#XmlElement(name = "flightOption")
private List<FlightOption> flightOption;
public FlightOptions() {
this.flightOption = new ArrayList();
}
public List<FlightOption> getFlightOption() {
return flightOption;
}
public void setFlightOption(List<FlightOption> flightOption) {
this.flightOption = flightOption;
}
}
#XmlRootElement(name = "flightOption")
#XmlAccessorType(XmlAccessType.FIELD)
public class FlightOption {
#XmlElement(name = "viaIata")
private String viaIata;
#XmlElement(name = "fromDate")
private String fromDate;
#XmlElement(name = "toDate")
private String toDate;
#XmlElement(name = "fromTime")
private String fromTime;
#XmlElement(name = "toTime")
private String toTime;
#XmlElement(name = "flightNum")
private String flightNum;
#XmlElement(name = "class")
private String fclass;
#XmlElement(name = "flightlegs")
private List<FlightLeg> flightLegs;
#XmlElement(name = "prices")
private Prices prices;
public FlightOption() {
this.flightLegs = new ArrayList();
this.prices = new Prices();
}
getters and setters
#XmlRootElement (name = "prices")
#XmlAccessorType (XmlAccessType.FIELD)
public class Prices {
#XmlElement (name ="adult")
private float adult;
#XmlElement (name ="child")
private float child;
#XmlElement (name = "infant")
private float infant;
#XmlElement (name = "total")
private Total total;
getters and setters
#XmlRootElement (name = "total")
#XmlAccessorType (XmlAccessType.FIELD)
public class Total {
#XmlAttribute (name ="serviceCharge")
private float serviceCharge;
#XmlAttribute (name = "taxCharge")
private float taxCharge;
#XmlAttribute (name ="taxGeneral")
private float taxGeneral;
#XmlAttribute (name = "totalPrice")
private float totalPrice;
#XmlAttribute (name ="currency")
private String currency;
getters and setters
REST response
<availabilityResponse version="3">
<flightList fromIata="FRA" toIata="YYZ" flightsFound="8">
<flightOptions>
<flightOption>
<viaIata>FRA-YHZ-YYZ</viaIata>
<fromDate>2015-06-06</fromDate>
<fromTime>13:15:00</fromTime>
<toDate>2015-06-06</toDate>
<toTime>20:10:00</toTime>
<flightNum>DEA062</flightNum>
<class>C</class>
<flightlegs>
<flightlegdetail fromIata="FRA" toIata="YHZ">
<fromDate>2015-06-06</fromDate>
<fromTime>13:15:00</fromTime>
<toDate>2015-06-06</toDate>
<toTime>15:35:00</toTime>
<flightNum>DE6062</flightNum>
</flightlegdetail>
</flightlegs>
<flightlegs>
<flightlegdetail fromIata="YHZ" toIata="YYZ">
<fromDate>2015-06-06</fromDate>
<fromTime>18:50:00</fromTime>
<toDate>2015-06-06</toDate>
<toTime>20:10:00</toTime>
<flightNum>WS269</flightNum>
</flightlegdetail>
</flightlegs>
<prices currency="EUR" specialOffer="true">
<adult>724.22</adult>
<child>725.00</child>
<infant>73.00</infant>
<total serviceCharge="0.00" taxCharge="85.77" taxGeneral="85.77"
flightPrice="724.22" totalPrice="809.99" currency="EUR" />
</prices>
</flightOption>
<flightOption>
<viaIata>FRA-YYZ</viaIata>
.....
Your exception is because you have not registered message convertors for handling xml responses returned from the service. You can use xstream marshallers etc and there are plenty of example out there in web.
http://www.informit.com/guides/content.aspx?g=java&seqNum=546
https://spring.io/blog/2009/03/27/rest-in-spring-3-resttemplate

Resources