I currently have an application that I'm attempting to diagnose what in the setup I've done incorrectly, and am not having any luck in determining why it's not working outside of very specific situations.
First the code that I'm using.
Configuration.java
#EnableBatchProcessing
#SpringBootApplication(scanBasePackages="com.lcbo")
#EnableIntegration
public class COnfig {
#Autowired
private JobBuilderFactory jobBuilderFactory;
#Autowired
private StepBuilderFactory stepBuilderFactory;
#Autowired
private LCBOInventoryTrackerProperties inventoryTrackerProperties;
#Bean
public Job processLCBOInventory(#Qualifier("getLCBOStoreDataStep") final Step getLCBOStoreDataStep) {
return jobBuilderFactory
.get("processLCBOInventory")
.incrementer(new RunIdIncrementer())
.start(getLCBOStoreDataStep)
.build();
}
/**
* This tasklet downloads the .zip file, unzips, and saves it in the appropriate folder under resources.
* Execute at 6am daily
*
// * #param AcquireDataFileTasklet acquireDataFiles
* #return Step - returns Step status; either SUCCESS or FAILURE
*/
#Bean
public Step getCurrentLCBODataStep(final AcquireDataFileTasklet acquireDataFiles,
final ExecutionContextPromotionListener listener) {
return stepBuilderFactory
.get("getCurrentLCBODataStep")
.tasklet(acquireDataFiles)
.allowStartIfComplete(true)
.listener(listener)
.build();
}
#Bean
public Step getLCBOStoreDataStep(final LCBOStoreReader lcboStoreReader,
final LCBOStoreWriter lcboStoreWriter) {
return stepBuilderFactory
.get("getLCBOStoreDataStep")
.<LCBOStore, LCBOStore>chunk(inventoryTrackerProperties.getDefaults().getChunkSize())
.reader(lcboStoreReader)
.writer(lcboStoreWriter)
.build();
}
}
The reader class
#Component
public class LCBOStoreReader extends AbstractLCBOReader implements ItemReader, InterstepDataRetriever {
private static final Logger log = LoggerFactory.getLogger(LCBOStoreReader.class);
#Override
public ItemReader<LCBOStore> read() throws UnexpectedInputException, ParseException, NonTransientResourceException {
Class<LCBOStore> classType = LCBOStore.class;
return createCSVReader(classType, currentCSVFilePath, inventoryTrackerProperties.getLCBOFilPropertiess().getStores());
}
/*
#Override
public void beforeStep(final StepExecution stepExecution) {
JobExecution jobExecution = stepExecution.getJobExecution();
ExecutionContext jobContext = jobExecution.getExecutionContext();
this.currentWorkingDate = (String) jobContext.get("currentWorkingDateKey");
}
*/
#Override
public void retrieveInterstepDataFromJobContext(final ExecutionContext jobContext) {
this.currentCSVFilePath = (String) jobContext.get("currentCSVFilePathKey");
}
}
and the class it extends (because the FlatFileItemReader setup is used by multiple readers)
public abstract class AbstractLCBOReader {
#Autowired
protected LCBOInventoryTrackerProperties inventoryTrackerProperties;
protected String currentCSVFilePathKey;
protected String currentCSVFilePath;
private static final Logger log = LoggerFactory.getLogger(AbstractLCBOReader.class);
protected <T> ItemReader<T> createCSVReader(final Class<T> classType,
final String currentCSVFilePath,
final LCBOFileDetailsProperties properties) {
FlatFileItemReader<T> reader = new FlatFileItemReader<>();
// Skip a line to ignore the header information in these files
reader.setLinesToSkip(properties.getNumberOfLinesToSkipInFile());
reader.setResource(new FileSystemResource(currentCSVFilePath + File.separator + properties.getFileName()));
reader.setLineMapper(createLineMapper(classType, properties));
reader.setRecordSeparatorPolicy(new DefaultRecordSeparatorPolicy());
reader.setEncoding("utf8");
return reader;
}
private <T> LineMapper<T> createLineMapper(final Class<T> classType, final LCBOFileProperties.LCBOFileDetailsProperties properties) {
DefaultLineMapper<T> lineMapper = new DefaultLineMapper<>();
lineMapper.setLineTokenizer(createLineTokenizer(properties));
lineMapper.setFieldSetMapper(createFieldSetMapper(classType));
return lineMapper;
}
private <T> FieldSetMapper<T> createFieldSetMapper(final Class<T> classType) {
BeanWrapperFieldSetMapper<T> fieldSetMapper = new BeanWrapperFieldSetMapper<>();
fieldSetMapper.setTargetType(classType);
return fieldSetMapper;
}
private LineTokenizer createLineTokenizer(final LCBOFileProperties.LCBOFileDetailsProperties properties) {
LCBOFileProperties.Column[] columns = properties.getColumns();
int[] columnIndexes = new int[columns.length];
String[] columnNames = new String[columns.length];
// populating the columnIndexes
for (int i = 0; i < columns.length; i++) {
columnIndexes[i] = columns[i].getColumnIndex();
columnNames[i] = columns[i].getColumnName();
}
DelimitedLineTokenizer lineTokenizer = new DelimitedLineTokenizer();
lineTokenizer.setIncludedFields(columnIndexes);
lineTokenizer.setNames(columnNames);
lineTokenizer.setDelimiter(",");
lineTokenizer.setQuoteCharacter('"');
return lineTokenizer;
}
}
The error when executing this will be that the object cannot be cast from FlatFileItemreader to the object passed as the first parameter in createCSVReader. Here's an example.
public class LCBOStore {
private Long id;
private String addressLineOne;
private String addressLineTwo;
private String city;
private String postalCode;
private String latitude;
private String longitude;
private String updatedAt; //Convert to Date
public LCBOStore(final Long id, final String addressLineOne, final String addressLineTwo, final String city,
final String postalCode, final String latitude, final String longitude, final String updatedAt) {
this.id = id;
this.addressLineOne = addressLineOne;
this.addressLineTwo = addressLineTwo;
this.city = city;
this.postalCode = postalCode;
this.latitude = latitude;
this.longitude = longitude;
this.updatedAt = updatedAt;
}
public Long getId() {
return id;
}
public String getAddressLineOne() {
return addressLineOne;
}
public String getAddressLineTwo() {
return addressLineTwo;
}
public String getCity() {
return city;
}
public String getPostalCode() {
return postalCode;
}
public String getLatitude() {
return latitude;
}
public String getLongitude() {
return longitude;
}
public String getUpdatedAt() {
return updatedAt;
}
public void setId(final Long id) {
this.id = id;
}
public void setAddressLineOne(final String addressLineOne) {
this.addressLineOne = addressLineOne;
}
public void setAddressLineTwo(final String addressLineTwo) {
this.addressLineTwo = addressLineTwo;
}
public void setCity(final String city) {
this.city = city;
}
public void setPostalCode(final String postalCode) {
this.postalCode = postalCode;
}
public void setLatitude(final String latitude) {
this.latitude = latitude;
}
public void setLongitude(final String longitude) {
this.longitude = longitude;
}
public void setUpdatedAt(final String updatedAt) {
this.updatedAt = updatedAt;
}
#Override
public String toString() {
return "StoreDBModel [id=" + id + ", addressLineOne=" + addressLineOne + ", city=" + city
+ ", postalCode=" + postalCode + ", latitude=" + latitude + ", longitude="
+ longitude + ", updatedAt=" + updatedAt + "]";
}
}
Now if I move the FlatFileItemReader mode that exists in createCSVReader into the constructor of the custom Reader class, or have it so it's in the configuration file, it works fine. However, I couldn't figure out how to work with job and step context in those configurations (the constructor executes before you can access step and jobContext it seems from my testing, and I could never figure how to access when put in the Config class.). Plus to me at least, it looks cleaner to have the Reader code in it's own file not being stuffed in the constructor.
So in a nutshell, is there a way to fix this os that having it in it's own reader class would work? Am I doing this incorrectly and using bad practices? Maybe a mix of the two? If there's anything missing please ask away and I'll attempt to clarify.
So I found the answer to be very simple with some help from those in the comments. Here's my solution.
First, add the bolded code to the abstract class createCSVWriter method
**protected <T> T** createCSVReader(final Class<T> classType,
final String currentCSVFilePath,
final LCBOFileDetailsProperties properties) throws Exception {
FlatFileItemReader<T> reader = new FlatFileItemReader<>();
// Skip a line to ignore the header information in these files
reader.setLinesToSkip(properties.getNumberOfLinesToSkipInFile());
reader.setResource(new FileSystemResource(currentCSVFilePath + File.separator + properties.getFileName()));
reader.setLineMapper(createLineMapper(classType, properties));
reader.setRecordSeparatorPolicy(new DefaultRecordSeparatorPolicy());
reader.setEncoding("utf8");
**return reader.read();**
}
Doing the read call manually will prevent it returning more then needed for your reader class. Then in the reader class edit the following
#Override
public **LCBOStore** read() throws **Exception**, UnexpectedInputException, ParseException, NonTransientResourceException {
Class<LCBOStore> classType = LCBOStore.class;
return createCSVReader(classType, currentCSVFilePath, inventoryTrackerProperties.getLCBOFilPropertiess().getStores());
}
This just returns the object you've created and hence issue resolved.
Related
I am Trying to write test case for a method which takes URI as input and maps with modelmapper.
however, I am getting null pointer exception for this.
I have added every possible implementaion of class which I want to test.
if you guy's need more for compilation tell me in comment section.
this one is actual implementation which I want to mock
#Override
public ApplicationScanConfigDTO getApplicationScanConfig(int account_id, String appAppScanConfigId) {
URI getUri = UriComponentsBuilder.fromPath("/").pathSegment("api/scheduleOnDemand")
.queryParam("Account_Id", account_id).queryParam("applicationConfigScanId", appAppScanConfigId).build()
.toUri();
return modelMapper.map(apiClient.getOperation(getUri, Object.class), ApplicationScanConfigDTO.class);
}
This is what I was trying
#Test
void testGetApplicationScanConfig() throws Exception {
URI getUri = new URI("/api/scheduleOnDemand?Account_Id=1&applicationConfigScanId=1");
modelmapper.map(restTemplate.getForEntity(getUri, JSONObject.class), ApplicationScanConfigDTO.class);
}
apiclient implementation
#Override
public <R> R getOperation(URI uri, Class<R> rClasss) {
URI builder = UriComponentsBuilder.fromHttpUrl(baseUrl)
.path(uri.getPath())
.query(uri.getQuery())
.build()
.toUri();
return restTemplate.getForObject(builder, rClasss);
}
ApplicationConfigDTO actual implementation:
public class ApplicationScanConfigDTO {
private Integer id;
private String serverName;
private Integer accountId;
private String ipAddress;
private String subnetRange;
private Integer credentialId;
private String credentialName;
private String os;
private List<String> ibmLibrary;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getServerName() {
return serverName;
}
public void setServerName(String serverName) {
this.serverName = serverName;
}
public Integer getAccountId() {
return accountId;
}
public void setAccountId(Integer accountId) {
this.accountId = accountId;
}
public String getIpAddress() {
return ipAddress;
}
public void setIpAddress(String ipAddress) {
this.ipAddress = ipAddress;
}
public String getSubnetRange() {
return subnetRange;
}
public void setSubnetRange(String subnetRange) {
this.subnetRange = subnetRange;
}
public Integer getCredentialId() {
return credentialId;
}
public void setCredentialId(Integer credentialId) {
this.credentialId = credentialId;
}
public String getCredentialName() {
return credentialName;
}
public void setCredentialName(String credentialName) {
this.credentialName = credentialName;
}
public String getOs() {
return os;
}
public void setOs(String os) {
this.os = os;
}
public List<String> getIbmLibrary() {
return ibmLibrary;
}
public void setIbmLibrary(List<String> ibmLibrary) {
this.ibmLibrary = ibmLibrary;
}
}
We have a batch job to load millions of Employee data with multiple address, It is failing to load few rows when I use chunk.
For example if I use chunk 5 and we loose 6th record which is associate to 5th row employee(refer image)
Please suggest a solution. Here is the Spring Batch code
#Configuration
public class EmployeeJobMyBatis {
#Autowired
private JobBuilderFactory jobBuilderFactory;
#Autowired
private StepBuilderFactory stepBuilderFactory;
#Autowired
private EmployeeDataSourceConfig datasourceConfig;
EmployeeRowMapper rowMapper = null;
private static final Logger LOG = LogManager.getLogger(EmployeeJobMyBatis.class);
#Bean
#Qualifier("MyBatisJob")
public Job mybatisJob() throws Exception {
return this.jobBuilderFactory.get("MyBatisJob").incrementer(new RunIdIncrementer())
.start(step()).build();
}
#Bean
public Step step() throws SQLException, Exception {
return this.stepBuilderFactory.get("EmployeeDataReadStep").<Employee, String>chunk(5)
.reader(reader()).processor(processor()).writer(writer())
.build();
}
#Bean
public SqlSessionFactory sqlSessionFactory() throws Exception {
PathMatchingResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver();
SqlSessionFactoryBean ss = new SqlSessionFactoryBean();
ss.setDataSource(datasourceConfig.getDataSource());
ss.setMapperLocations(resourcePatternResolver.getResources("employee.xml"));
org.apache.ibatis.session.Configuration configuration = new org.apache.ibatis.session.Configuration();
configuration.setDefaultExecutorType(ExecutorType.BATCH);
ss.setConfiguration(configuration);
return ss.getObject();
}
#Bean
public MyBatisCursorItemReader<Employee> reader() throws Exception {
MyBatisCursorItemReader<Employee> reader = new MyBatisCursorItemReader<Employee>();
reader.setSqlSessionFactory(sqlSessionFactory());
reader.setQueryId("EmployeeData");
return reader;
}
#Bean
public processor processor() {
return new DataProcessor();
}
#Bean
public MultiResourceItemWriter<String> writer() {
MultiResourceItemWriter<String> writer = new MultiResourceItemWriter<String>();
writer.setResource(new FileSystemResource("C:/data/Employee.json"));
writer.setItemCountLimitPerResource(2500000);
FlatFileItemWriter<String> fileWriter = new FlatFileItemWriter<String>();
fileWriter.setLineAggregator(new MyDelimitedLineAggregator());
writer.setDelegate(fileWriter);
return writer;
}
}
public class DataProcessor implements ItemProcessor<Employee, String> {
private static final Gson gson = new GsonBuilder().create();
#Override
public String process(Employee employee) throws Exception {
if (employee != null && employee.getId() == null)
return null;
else
return (String) (gson.toJson(employee));
}
}
public class MyDelimitedLineAggregator extends DelimitedLineAggregator<String> {
String returnString = "";
#Override
public String aggregate(String jsonstr) {
if(jsonstr != null)
returnString = jsonstr;
return returnString;
}
}
public class Employee{
String emplId;
Addresses addressList;
public String getEmplId() {
return emplId;
}
public void setEmplId(Addresses value) {
this.emplId = value;
}
public Addresses getAddressList() {
return addressList;
}
public void setAddressList(Addresses value) {
this.addressList = value;
}
}
public class Addresses{
List<Address> addresses;
public List<Address> getAddresses() {
if (addresses == null) {
addresses = new ArrayList<Address>();
}
return this.addresses;
}
}
public class Address{
String addressLineOne;
String city;
String country;
public String getAddressLineOne(){
return addressLineOne;
}
public void setAddressLineOne(String value) {
this.addressLineOne = value;
}
public String getCity(){
return city;
}
public void setCity(String value) {
this.city = value;
}
public String getCountry(){
return country;
}
public void setCountry(String value) {
this.country = value;
}
}
Here is the MyBatis Mapper xml
Employee.xml
<resultMap id="EmployeeMap" type="Employee">
<id column="emplId" property="emplId"/>
<collection property="addressList.addresses"
javaType="list" ofType="Address">
<result column="addressLineOne" property="addressLineOne"/>
<result column="city" property="city"/>
<result column="country" property="country"/>
</collection>
</resultMap>
<select id="employeeData" resultMap="EmployeeMap">select * from employee e left join address a on a.emplId = e.emplId</select>
A chunk oriented step reads rows one by one and map each one to a domain object (basically one to one mapping). In your case, you have a one to many relation. So your step configuration won't work as it is now. What you need to do is implement the driving query pattern as follows:
Make the reader reads employee details except addresses
Use an item processor that fetches addresses for the current employee
Edit: Add an example
import javax.sql.DataSource;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.JobParameters;
import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing;
import org.springframework.batch.core.configuration.annotation.JobBuilderFactory;
import org.springframework.batch.core.configuration.annotation.StepBuilderFactory;
import org.springframework.batch.core.launch.JobLauncher;
import org.springframework.batch.item.ItemProcessor;
import org.springframework.batch.item.ItemWriter;
import org.springframework.batch.item.database.JdbcCursorItemReader;
import org.springframework.batch.item.database.builder.JdbcCursorItemReaderBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType;
#Configuration
#EnableBatchProcessing
public class MyJob {
#Bean
public DataSource dataSource() {
return new EmbeddedDatabaseBuilder()
.setType(EmbeddedDatabaseType.H2)
.addScript("/org/springframework/batch/core/schema-drop-h2.sql")
.addScript("/org/springframework/batch/core/schema-h2.sql")
.build();
}
#Bean
public JdbcTemplate jdbcTemplate(DataSource dataSource) {
return new JdbcTemplate(dataSource);
}
#Bean
public JdbcCursorItemReader<Person> itemReader() {
return new JdbcCursorItemReaderBuilder<Person>()
.name("personItemReader")
.dataSource(dataSource())
.sql("select id, name from person")
.beanRowMapper(Person.class)
.build();
}
#Bean
public ItemProcessor<Person, Person> itemProcessor() {
return new ItemProcessor<Person, Person>() {
#Autowired
private JdbcTemplate jdbcTemplate;
#Override
public Person process(Person person) {
Address address = jdbcTemplate.queryForObject("select * from address where personId = ?", new Object[]{person.getId()}, new BeanPropertyRowMapper<>(Address.class));
person.setAddress(address);
return person;
}
};
}
#Bean
public ItemWriter<Person> itemWriter() {
return items -> {
for (Person item : items) {
System.out.println("item = " + item);
}
};
}
#Bean
public Job job(JobBuilderFactory jobs, StepBuilderFactory steps) {
return jobs.get("job")
.start(steps.get("step")
.<Person, Person>chunk(2)
.reader(itemReader())
.processor(itemProcessor())
.writer(itemWriter())
.build())
.build();
}
public static void main(String[] args) throws Exception {
ApplicationContext context = new AnnotationConfigApplicationContext(MyJob.class);
JdbcTemplate jdbcTemplate = context.getBean(JdbcTemplate.class);
jdbcTemplate.update("CREATE TABLE address (id INT IDENTITY NOT NULL PRIMARY KEY, personId INT, street VARCHAR(20));");
jdbcTemplate.update("CREATE TABLE person (id INT IDENTITY NOT NULL PRIMARY KEY, name VARCHAR(20));");
jdbcTemplate.update("INSERT INTO address (id, personId, street) VALUES (1,1, 'oxford street');");
jdbcTemplate.update("INSERT INTO address (id, personId, street) VALUES (2,2, 'howard street');");
jdbcTemplate.update("INSERT INTO person (id, name) VALUES (1, 'foo');");
jdbcTemplate.update("INSERT INTO person (id, name) VALUES (2, 'bar');");
JobLauncher jobLauncher = context.getBean(JobLauncher.class);
Job job = context.getBean(Job.class);
jobLauncher.run(job, new JobParameters());
}
public static class Person {
private long id;
private String name;
private Address address;
public Person() {
}
public Person(long id, String name) {
this.id = id;
this.name = name;
}
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Address getAddress() {
return address;
}
public void setAddress(Address address) {
this.address = address;
}
#Override
public String toString() {
return "Person{" +
"id=" + id +
", name='" + name + '\'' +
", address=" + address +
'}';
}
}
public static class Address {
private int id;
private int personId;
private String street;
public Address() {
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getStreet() {
return street;
}
public void setStreet(String street) {
this.street = street;
}
public int getPersonId() {
return personId;
}
public void setPersonId(int personId) {
this.personId = personId;
}
#Override
public String toString() {
return "Address{" +
"id=" + id +
", street='" + street + '\'' +
'}';
}
}
}
This example reads person/address data. The reader reads only the person's id and name, and a processor fetches the address for the current item.
I want to receive all challenges in Firestore and loop over result to add it to an ArrayList.
db.collection("challenges")
.get()
.addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() {
#Override
public void onComplete(#NonNull Task<QuerySnapshot> task) {
if (task.isSuccessful()) {
for (DocumentSnapshot document : task.getResult()) {
if (document.exists()) {
Log.d(TAG, document.getId() + " => " + document.getData());
Error-> Challenge challenge = document.toObject(Challenge.class);
Log.d(TAG, challenge.getUid() + " => " + challenge.getText());
challengeList.add(document.getData().toString());
}
}
challengeListView.setAdapter(challengeArrayAdapter);
} else {
Log.d(TAG, "Error getting documents: ", task.getException());
}
}
});
Error is:
java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.Object java.lang.reflect.Constructor.newInstance(java.lang.Object[])' on a null object reference
Line:
Challenge challenge = document.toObject(Challenge.class);
The log with Log.d(TAG, document.getId() + " => " + document.getData());
is working.
Reference: https://firebase.google.com/docs/firestore/query-data/get-data#get_all_documents_in_a_collection
This is my my Challenge Class:
public class Challenge {
private Date createdAt;
private Date changedAt;
private String uid;
private String text;
private double longitude;
private double latitude;
public Challenge(String uid, String text, double longitude, double latitude) {
Date currentDate = new Date();
this.createdAt = currentDate;
this.changedAt = currentDate;
this.uid = uid;
this.text = text;
this.longitude = longitude;
this.latitude = latitude; }
public Date getCreatedAt() { return createdAt; }
public Date getChangedAt() { return changedAt; }
public String getUid() { return uid; }
public String getText() { return text; }
public double getLongitude() { return longitude; }
public double getLatitude() { return latitude;}
}
You need to change this line of code:
Challenge challenge = document.toObject(Challenge.class);
with
Map<String, Object> map = task.getResult().getData());
To use toObject() method for a single document, please use the following code:
DocumentReference docRef = db.collection("challenges").document("yourDocument");
docRef.get().addOnSuccessListener(new OnSuccessListener<DocumentSnapshot>() {
#Override
public void onSuccess(DocumentSnapshot documentSnapshot) {
Challenge challenge = documentSnapshot.toObject(Challenge.class);
}
});
The error is because of your modell class. Your code looks good. Add the no-argument constructor in your model class. Keep that code or use the Map<String, Object> and your problem will be solved.
To add the no-argument constructor, please add the following line of code in your model class:
public Challenge() {} //Needed for Firebase
after the decalaration of class variables.
I know it is too late but it may help some one in my case my object was
public class RFQ {
public String content,email,receiverKey,productKey,companyKey;
public Sender sender;
public Long createAt;
public RFQ() {
}
public RFQ(String content, String email, String receiverKey, String productKey, String companyKey, Sender sender, Long createAt) {
this.content = content;
this.email = email;
this.receiverKey = receiverKey;
this.productKey = productKey;
this.companyKey = companyKey;
this.sender = sender;
this.createAt = createAt;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public Long getCreateAt() {
return createAt;
}
public void setCreateAt(Long createAt) {
this.createAt = createAt;
}
public String getReceiverKey() {
return receiverKey;
}
public void setReceiverKey(String receiverKey) {
this.receiverKey = receiverKey;
}
public String getProductKey() {
return productKey;
}
public void setProductKey(String productKey) {
this.productKey = productKey;
}
public String getCompanyKey() {
return companyKey;
}
public void setCompanyKey(String companyKey) {
this.companyKey = companyKey;
}
public Sender getSender() {
return sender;
}
public void setSender(Sender sender) {
this.sender = sender;
}
}
Everything is proper here but still, I was getting the error that was due to my Sender class in my Sender class I missed to place non-args constructor.
Bro, you need to add Default Constructor in your Challenge Model class as it is needed for Firebase
public Challenge() {} //add this line
I am attempting to use Camel's bindy annotation to parse through a CSV. I have followed some tutorials online but cannnot seem to get them to work. I am new to this side of camel, so I dont quite understand the errors I am getting. For right now my CSV is very simple as I am just trying to understand how this functionallity works.
The CSV currently looks likes this:
HDR|Suborg|CountryCode|BrokerFile|Batch|Time|Date|
The Error Im getting it this:
org.apache.camel.RuntimeCamelException: java.lang.InstantiationException: com.ups.ttg.bsis.fromdos.AlamoHdr
Here is my code:
public class AlamoPipeRouteBuilder extends RouteBuilder {
final DataFormat bindy = new BindyCsvDataFormat(AlamoHdr.class);
/*
* Endpoints
*/
#EnforceInitialization
private Logging logging;
#EnforceInitialization
private RatingProfileAlamoSplitHandler ratingProfileAlamoSplitHandler;
#EnforceInitialization
private String start = "";
#EnforceInitialization
private String end = "";
#Override
public void configure() throws Exception {
System.out.println("Started Configure Method");
/*
* Basic Route
*/
from(start)
.setExchangePattern(ExchangePattern.InOnly)
.routeId("processRatingProfile.alamo")
//.beanRef("RatingProfileExchangeUtilies", "checkForNoRecords(*)")
.beanRef("logging", "debug(*, 'Starting aggregation strategy loop...')")
.split(body().tokenize("\n"), ratingProfileAlamoSplitHandler).streaming()
.unmarshal(bindy)
.setHeader("INDEX", simple("${header.CamelSplitIndex}") )
.setHeader("COMPLETE", simple("${header.CamelSplitComplete}") )
.end()
.beanRef("logging", "debug(*, 'Aggregation strategy loop complete...')")
.removeHeader("lastRatingProfile")
.to(end);
}
public void setStart(String start) {
this.start = start;
}
public void setEnd(String end) {
this.end = end;
}
public void setRatingProfileAlamoSplitHandler(RatingProfileAlamoSplitHandler ratingProfileAlamoSplitHandler) {
this.ratingProfileAlamoSplitHandler = ratingProfileAlamoSplitHandler;
}
public void setLogging(Logging logging) {
this.logging = logging;
}
}
public class RatingProfileAlamoSplitHandler implements AggregationStrategy {
#EnforceInitialization
private static Logging logging;
public Exchange aggregate(Exchange oldExchange, Exchange newExchange) {
Integer currIndex = -1;
boolean lastLine = false;
if(newExchange != null) {
currIndex = (Integer) newExchange.getIn().getHeader("INDEX");
System.out.println("THIS IS THE INDEX: " + currIndex);
/*lastLine = (Boolean) newExchange.getIn().getHeader("COMPLETE");
System.out.println("THIS IS THE COMPLETE: " + lastLine);*/
System.out.println("This IS THE BODY: " + newExchange.getIn().getBody());
if(currIndex == 0) {
AlamoHdr alamoHdr = (AlamoHdr) newExchange.getIn().getBody();
}
}
return newExchange;
}
public static void setLogging(Logging logging) {
RatingProfileAlamoSplitHandler.logging = logging;
}
}
public class AlamoHdr implements InitializingBean, DisposableBean {
#DataField(pos = 2, trim = true)
private String suborg;
#DataField(pos = 3, trim = true)
private String countryCode;
#DataField(pos = 4, trim = true)
private String brokerFile;
#DataField(pos = 5, trim = true)
private String batch;
#DataField(pos = 6, trim = true)
private String time;
#DataField(pos = 7, trim = true)
private String date;
public AlamoHdr(String suborg, String countryCode, String brokerFile, String batch, String time, String date) {
super();
this.suborg = suborg;
this.countryCode = countryCode;
this.brokerFile = brokerFile;
this.batch = batch;
this.time = time;
this.date = date;
}
public String getSuborg() {
return suborg;
}
public void setSuborg(String suborg) {
this.suborg = suborg;
}
public String getCountryCode() {
return countryCode;
}
public void setCountryCode(String countryCode) {
this.countryCode = countryCode;
}
public String getBrokerFile() {
return brokerFile;
}
public void setBrokerFile(String brokerFile) {
this.brokerFile = brokerFile;
}
public String getBatch() {
return batch;
}
public void setBatch(String batch) {
this.batch = batch;
}
public String getTime() {
return time;
}
public void setTime(String time) {
this.time = time;
}
public String getDate() {
return date;
}
public void setDate(String date) {
this.date = date;
}
#Override
public String toString() {
return "AlamoHdr [suborg=" + suborg + ", countryCode=" + countryCode + ", brokerFile=" + brokerFile + ", batch="
+ batch + ", time=" + time + ", date=" + date + "]";
}
public void destroy() throws Exception {
// TODO Auto-generated method stub
}
public void afterPropertiesSet() throws Exception {
// TODO Auto-generated method stub
}
}
For anyone who may also come across this problem, I found what was going wrong. When using a | as your separator you need to pass it in like so
#CsvRecord(separator = "\\|", skipFirstLine = false)
because the | is a meta character that represents the OR operation and we need a regular expression for this operation.
Also you cannot have a constructor in files like AlamoHdr because the variables are being populated through the binding not through calling the constructor.
I have an application (Spring 4 MVC+Hibernate 4+MySQL+Maven integration example using annotations) , integrating Spring with Hibernate using annotation based configuration.
Here my controller:
#Controller
public class RestController {
#RequestMapping(value = { "/restCallBack" }, method = RequestMethod.GET)
#ResponseBody
public String performCallBack(#RequestBody RestCallBack restCallBack) {
Preconditions.checkNotNull( restCallBack );
return "computerList";
}
but when I put this on the browser I get a 400:
http://localhost:8080/myApp/restCallBack?devideId=devideId&time=time&duplicate=duplicate&snr=snr&station=station&data=data&avgSignal=avgSignal&lat=lat&lng=lng&rssi=rssi&seqNumber=seqNumber
Here the RestCallBack class
public class RestCallCallBack {
private String devideId;
private String time;
private String duplicate;
private String snr;
private String station;
private String data;
private String avgSignal;
private String lat;
private String lng;
private String rssi;
private String seqNumber;
public String getDevideId() {
return devideId;
}
public void setDevideId(String devideId) {
this.devideId = devideId;
}
public String getTime() {
return time;
}
public void setTime(String time) {
this.time = time;
}
public String getDuplicate() {
return duplicate;
}
public void setDuplicate(String duplicate) {
this.duplicate = duplicate;
}
public String getSnr() {
return snr;
}
public void setSnr(String snr) {
this.snr = snr;
}
public String getStation() {
return station;
}
public void setStation(String station) {
this.station = station;
}
public String getData() {
return data;
}
public void setData(String data) {
this.data = data;
}
public String getAvgSignal() {
return avgSignal;
}
public void setAvgSignal(String avgSignal) {
this.avgSignal = avgSignal;
}
public String getLat() {
return lat;
}
public void setLat(String lat) {
this.lat = lat;
}
public String getLng() {
return lng;
}
public void setLng(String lng) {
this.lng = lng;
}
public String getRssi() {
return rssi;
}
public void setRssi(String rssi) {
this.rssi = rssi;
}
public String getSeqNumber() {
return seqNumber;
}
public void setSeqNumber(String seqNumber) {
this.seqNumber = seqNumber;
}
}
Based on the example request query string, it seems like you are attempting to pass request parameters to the server rather than a request body. If so, take a look at #RequestParam, e.g.
#Controller
public class RestController {
#RequestMapping(value = { "/restCallBack" }, method = RequestMethod.GET)
#ResponseBody
public String performCallBack(#RequestParam("devideId") String devideId,
#RequestParam("time") String time,
#RequestParam("duplicate") String duplicate,
/* more request params... */ {
RestCallCallBack restCallCallBack = new RestCallCallBack();
restCallCallBack.setDevideId(devideId);
restCallCallBack.setTime(time);
restCallCallBack.setDuplicate(duplicate);
// set more params...
// perform validation
return "computerList";
}
}
You can also specify which params are optional by by setting the #RequestParam's required attribute to false.
More information available in the Binding request parameters to method parameters with #RequestParam paragraph in the Spring Reference docs.