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.
Related
I developed Spring Boot CRUD application. The database I have connected is PostgreSQL. #GetMapping is working properly and an empty array of objects can be retrieved by the GET request. But in #PostMapping, the POST request gives a 404 error.
đź“ŚSpringRecapApplication.java
package com.example.SpringRecap;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration;
import org.springframework.web.bind.annotation.*;
import java.util.List;
#RestController
#SpringBootApplication(exclude = SecurityAutoConfiguration.class)
//#RequestMapping("api/v1/customers")
//#EnableWebMvc
#RequestMapping(name = "api/v1/customers" ,method = RequestMethod.POST)
public class SpringRecapApplication {
//dependency injection
private static CustomerRepository customerRepository;
public SpringRecapApplication(CustomerRepository customerRepository) {
this.customerRepository = customerRepository;
}
public static void main(String[] args) {
SpringApplication.run(SpringRecapApplication.class, args);
}
#GetMapping
public List<Customer> getCustomer() {
return customerRepository.findAll();
}
record NewCustomerRequest(
String name,
String email,
Integer age
) {
#PostMapping
public void addCustomer(#RequestBody NewCustomerRequest newCustomerRequest) {
Customer customer = new Customer();
customer.setAge(newCustomerRequest.age());
customer.setName(newCustomerRequest.name());
customer.setEmail(newCustomerRequest.email());
customerRepository.save(customer);
}
}
}
customerRepository.save(customer); doesn't allow to make the dependency injection final. ( private static CustomerRepository customerRepository;). IDEA suggests making it static. But it didn't work. When I was using #RequestMapping("api/v1/customers"), a 405 error was received. Then I fixed that issue by doing as below,
#RequestMapping(name = "api/v1/customers" ,method = RequestMethod.POST)
đź“ŚCustomerRepository.java
package com.example.SpringRecap;
import org.springframework.data.jpa.repository.JpaRepository;
public interface CustomerRepository extends JpaRepository<Customer,Integer> {
}
đź“ŚCustomer.java
package com.example.SpringRecap;
import jakarta.persistence.*;
import java.util.Objects;
#Entity
public class Customer {
#Id
#SequenceGenerator(
name = "customer_id_sequence",
sequenceName = "customer_id_sequence",
allocationSize = 1
)
#GeneratedValue(
strategy = GenerationType.SEQUENCE,
generator = "customer_id_sequence"
)
private Integer id;
private String name;
private String email;
private Integer age;
public Customer(Integer id, String name, String email, Integer age) {
this.id = id;
this.name = name;
this.email = email;
this.age = age;
}
public Customer() {
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Customer customer = (Customer) o;
return Objects.equals(id, customer.id) && Objects.equals(name, customer.name) && Objects.equals(email, customer.email) && Objects.equals(age, customer.age);
}
#Override
public int hashCode() {
return Objects.hash(id, name, email, age);
}
#Override
public String toString() {
return "Customer{" +
"id=" + id +
", name='" + name + '\'' +
", email='" + email + '\'' +
", age=" + age +
'}';
}
}
Postman:
Please put a comment if further information is needed to get the solution.
The problem with your code is that you specified the POST endpoint as part of your DTO and not as part of your controller. As your DTO is not a Spring managed bean, Spring won't map the URL to your endpoint. Anyways, you should move your endpoints into a seperate class. Example:
#RestController
#RequestMapping("api/v1/customers")
public class CustomerController {
private final CustomerRepository customerRepository;
public SpringRecapApplication(CustomerRepository customerRepository) {
this.customerRepository = customerRepository;
}
#GetMapping
public List<Customer> getCustomer() {
return customerRepository.findAll();
}
#PostMapping
public void addCustomer(#RequestBody NewCustomerRequest newCustomerRequest) {
Customer customer = new Customer();
customer.setAge(newCustomerRequest.age());
customer.setName(newCustomerRequest.name());
customer.setEmail(newCustomerRequest.email());
customerRepository.save(customer);
}
// Helper classes
record NewCustomerRequest(String name, String email, Integer age) { }
}
It would be best if you moved your DTO in a seperate class as well. I recommend placing the DTOs in a dto package and your controllers in a controller package.
Two side notes: you shouldn't expose your entities via your API. You should use DTOs for incoming and outgoing data. Check out lombok and mapstruct, they make this pretty easy.
I have an issue related to hibernate level 2 cache. It works with getById method, but not other method:
This is my code:
jpa:
database-platform: org.hibernate.dialect.MySQL5InnoDBDialect
database: MYSQL
show-sql: true
properties:
hibernate.id.new_generator_mappings: true
hibernate.connection.provider_disables_autocommit: true
hibernate.cache.use_second_level_cache: true
hibernate.cache.use_query_cache: true
hibernate.cache.region.factory_class: com.mycompany.myapp.config.CustomRegionFactory
hibernate.generate_statistics: true
hibernate.cache.region_prefix: hibernate
hibernate.cache.use_structured_entries: true
#Configuration #EnableCaching public class CacheConfiguration {
#Bean
public javax.cache.configuration.Configuration<Object, Object> jcacheConfiguration(JHipsterProperties jHipsterProperties) {
MutableConfiguration<Object, Object> jcacheConfig = new MutableConfiguration<>();
Config config = new Config();
config.useSingleServer().setAddress(jHipsterProperties.getCache().getRedis().getServer());
jcacheConfig.setStatisticsEnabled(true);
jcacheConfig.setExpiryPolicyFactory(CreatedExpiryPolicy.factoryOf(new Duration(TimeUnit.SECONDS, jHipsterProperties.getCache().getRedis().getExpiration())));
return RedissonConfiguration.fromInstance(Redisson.create(config), jcacheConfig);
}
#Bean
public HibernatePropertiesCustomizer hibernatePropertiesCustomizer(javax.cache.CacheManager cm) {
return hibernateProperties -> hibernateProperties.put(ConfigSettings.CACHE_MANAGER, cm);
}
#Bean
public JCacheManagerCustomizer cacheManagerCustomizer(javax.cache.configuration.Configuration<Object, Object> jcacheConfiguration) {
return cm -> {
createCache(cm, com.mycompany.myapp.repository.UserRepository.USERS_BY_LOGIN_CACHE, jcacheConfiguration);
createCache(cm, com.mycompany.myapp.repository.UserRepository.USERS_BY_EMAIL_CACHE, jcacheConfiguration);
createCache(cm, com.mycompany.myapp.domain.User.class.getName(), jcacheConfiguration);
createCache(cm, com.mycompany.myapp.domain.Authority.class.getName(), jcacheConfiguration);
createCache(cm, com.mycompany.myapp.domain.User.class.getName() + ".authorities", jcacheConfiguration);
createCache(cm, com.mycompany.myapp.domain.Company.class.getName(), jcacheConfiguration);
// jhipster-needle-redis-add-entry
};
}
private void createCache(javax.cache.CacheManager cm, String cacheName, javax.cache.configuration.Configuration<Object, Object> jcacheConfiguration) {
javax.cache.Cache<Object, Object> cache = cm.getCache(cacheName);
if (cache != null) {
cm.destroyCache(cacheName);
}
cm.createCache(cacheName, jcacheConfiguration);
} }
public class CustomRegionFactory extends RedissonRegionFactory {
#Override
protected RedissonClient createRedissonClient(Map properties) {
Config config = new Config();
config.useSingleServer().setAddress("redis://127.0.0.1:6379").setRetryInterval(1500)
.setRetryAttempts(3).setConnectTimeout(10000)
.setClientName("client1");
return Redisson.create(config);
}
}
Entity:
package com.mycompany.myapp.domain;
import org.hibernate.annotations.Cache;
import org.hibernate.annotations.CacheConcurrencyStrategy;
import javax.persistence.*;
import java.io.Serializable;
/**
* A Company.
*/
#Entity
#Table(name = "company")
#Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
public class Company implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(name = "name")
private String name;
// jhipster-needle-entity-add-field - JHipster will add fields here, do not remove
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public Company name(String name) {
this.name = name;
return this;
}
public void setName(String name) {
this.name = name;
}
// jhipster-needle-entity-add-getters-setters - JHipster will add getters and setters here, do not remove
#Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (!(o instanceof Company)) {
return false;
}
return id != null && id.equals(((Company) o).id);
}
#Override
public int hashCode() {
return 31;
}
#Override
public String toString() {
return "Company{" +
"id=" + getId() +
", name='" + getName() + "'" +
"}";
}
}
Please help me
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 6 years ago.
Improve this question
[UML Diagram][1]
I'm studying for the midterm exam next week and I'm practicing some given examples from my professor; however, I am having some trouble with class return type methods.
I attached UML diagram just in case.
What i'm trying to understand is getPerson method in Job class. I don't think i need a array list in Job class to store all the employee. Because I have an array list already in Company class. Also return type is Employee class that I'm not sure how to get person's info using this class return type.
My problems
public Employee getPerson() {} in Job class
public boolean isVacant() {} in Job class
Also would you mind checking getVacantJobs, getFilledJobs, and getAllJobs methods if those are correctly built?
I used iterator to display all the stored jobs.
---------------------------Employee Class -----------------------------
public class Employee {
private String name;
private int id;
public Employee(int id, String name) {
this.name = name;
this.id =id;
}
public final String getName() {
return name;
}
public final void setName(String name) {
this.name = name;
}
public final int getId() {
return id;
}
public final void setId(int id) {
this.id = id;
}
#Override
public String toString() {
return "Employee [name=" + name + ", id=" + id + "]";
}
}
----------------------------Job Class--------------------------------------
public class Job {
private String description;
private int id;
private double maxSalary;
public Job(int id, double maxSalary, String description) {
this.description = description;
this.id = id;
this.maxSalary = maxSalary;
}
public Job(int id, double maxSalary, String description, Employee e1) {
this.description = description;
this.id = id;
this.maxSalary = maxSalary;
}
#Override
public String toString() {
return "Job [description=" + description + ", id=" + id
+ ", maxSalary=" + maxSalary + "]";
}
public final String getDescription() {
return description;
}
public final void setDescription(String description) {
this.description = description;
}
public final double getMaxSalary() {
return maxSalary;
}
public final void setMaxSalary(double maxSalary) {
this.maxSalary = maxSalary;
}
public final int getId() {
return id;
}
public Employee getPerson() {
retrun
}
public final void setPerson(Employee person) {
this.id = person.getId();
}
}
--------------------------Company Class ---------------------------
import java.util.ArrayList;
import java.util.Iterator;
public class Company {
static ArrayList list = new ArrayList();
Iterator itr = list.iterator();
private String name;
public Company(String name) {
this.name = name;
}
public Company() {
// TODO Auto-generated constructor stub
}
public static void addJob(Job j1) {
list.add(j1);
}
public void removeJob(int id) {
list.remove(id);
}
public ArrayList<Job> getVacantJobs() {
while (itr.hasNext()) {
if ((itr == null)) {
System.out.println(itr);
}
}
return null;
}
public ArrayList<Job> getFilledJobs() {
while (itr.hasNext()) {
if (!(itr == null)) {
System.out.println(itr);
}
}
return null;
}
public ArrayList<Job> getAllJobs() {
while (itr.hasNext()) {
System.out.println(itr.next());
}
return null;
}
}
Add field person to Job class.
public class Job {
// .....
private Employee person;
public Employee getPerson() {
return person;
}
public final void setPerson(Employee person) {
this.person = person;
}
public boolean isVacant() {
return person == null;
}
}
And add jobs field to Company class.
public class Company {
// static ArrayList list = new ArrayList(); // You don't need this
// Iterator itr = list.iterator(); // You don't need this.
// .....
private ArrayList<Job> jobs = new ArrayList<>();
public ArrayList<Job> getVacantJobs() {
ArrayList<Job> result = new ArrayList<>();
for (Job job : jobs)
if (job.isVacant())
result.add(job);
return result;
}
public ArrayList<Job> getFilledJobs() {
ArrayList<Job> result = new ArrayList<>();
for (Job job : jobs)
if (!job.isVacant())
result.add(job);
return result;
}
public ArrayList<Job> getAllJobs() {
ArrayList<Job> result = new ArrayList<>();
for (Job job : jobs)
result.add(job);
return result;
}
}
this weekend I tried out your great framework and would like to use it in production. Unfortunately my Employee Bean has an attribute sexuality which is of type enum. Somehow the integrated official ParseEnum cellprocessor cannot parse the sexuality attribute while reading from .csv file. Could you please look into this?
Error Message
Exception in thread "main" org.supercsv.exception.SuperCsvCellProcessorException: ' BI' could not be parsed as a enum of type test.supercsv.Sexuality
processor=org.supercsv.cellprocessor.ParseEnum
context={lineNo=2, rowNo=2, columnNo=5, rowSource=[1, Pankaj Kumar, CEO, 5,000USD, BI]}
at org.supercsv.cellprocessor.ParseEnum.execute(ParseEnum.java:146)
at org.supercsv.util.Util.executeCellProcessors(Util.java:93)
at org.supercsv.io.AbstractCsvReader.executeProcessors(AbstractCsvReader.java:203)
at org.supercsv.io.CsvBeanReader.readIntoBean(CsvBeanReader.java:261)
at org.supercsv.io.CsvBeanReader.read(CsvBeanReader.java:190)
at test.supercsv.Reading.readWithCsvBeanReader(Reading.java:35)
at test.supercsv.Reading.main(Reading.java:24)
PARTIAL CODE
enum CellProcessor
private static CellProcessor[] getProcessors() {
final CellProcessor[] processors = new CellProcessor[]{
new UniqueHashCode(), // ID (must be unique)
new NotNull(), // Name
new Optional(), // Role
new NotNull(), // Salary
new ParseEnum(Sexuality.class, true) // enum Sexuality
};
return processors;
}
First Employee object from csv file
1,Pankaj Kumar,CEO,"5,000USD", BI
FULL CODE
Employee Bean
package test.supercsv;
public class Employee {
private String id;
private String name;
private String role;
private String salary;
private Sexuality sexuality;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getRole() {
return role;
}
public void setRole(String role) {
this.role = role;
}
public String getSalary() {
return salary;
}
public void setSalary(String salary) {
this.salary = salary;
}
public Sexuality getSexuality() {
return sexuality;
}
public void setSexuality(Sexuality sexuality) {
this.sexuality = sexuality;
}
#Override
public String toString() {
return "Employee{" + "id=" + id + ", name=" + name + ", role=" + role + ", salary=" + salary
+ ", sexuality=" + sexuality.name()
+ '}';
}
}
enum Sexuality
package test.supercsv;
public enum Sexuality {
HETERO, HOMO, BI, TRANSGENDER;
}
CSVBeanReader
package test.supercsv;
import java.io.FileReader;
import java.io.IOException;
import org.supercsv.cellprocessor.Optional;
import org.supercsv.cellprocessor.ParseEnum;
import org.supercsv.cellprocessor.constraint.NotNull;
import org.supercsv.cellprocessor.constraint.UniqueHashCode;
import org.supercsv.cellprocessor.ift.CellProcessor;
import org.supercsv.io.CsvBeanReader;
import org.supercsv.io.ICsvBeanReader;
import org.supercsv.prefs.CsvPreference;
public class Reading {
private static final String CSV_FILENAME = "src/resources/employee.csv";
public static void main(String[] args) throws IOException {
readWithCsvBeanReader();
}
private static void readWithCsvBeanReader() throws IOException {
try (ICsvBeanReader beanReader = new CsvBeanReader(new FileReader(CSV_FILENAME), CsvPreference.STANDARD_PREFERENCE)) {
// the header elements are used to map the values to the bean (names must match)
final String[] header = beanReader.getHeader(true);
final CellProcessor[] processors = getProcessors();
Employee employee;
while ((employee = beanReader.read(Employee.class, header, processors)) != null) {
System.out.println(String.format("lineNo=%s, rowNo=%s, employee=%s",
beanReader.getLineNumber(),
beanReader.getRowNumber(),
employee));
}
}
}
private static CellProcessor[] getProcessors() {
final CellProcessor[] processors = new CellProcessor[]{
new UniqueHashCode(), // ID (must be unique)
new NotNull(), // Name
new Optional(), // Role
new NotNull(), // Salary
new ParseEnum(Sexuality.class, true) // enum Sexuality
};
return processors;
}
}
content of CSV-file
ID,Name,Role,Salary,Sexuality
1,Pankaj Kumar,CEO,"5,000USD", BI
2,Lisa,Manager,500USD, Homo
3,David,,1000USD, Hetero
Solution
just as Hound Dog has pointed out: the spaces in my csv-file were the cause of trouble. Just erase them and code works now!
ID,Name,Role,Salary,Sexuality
1,Pankaj Kumar,CEO,"5,000USD,BI
2,Lisa,Manager,500USD,Homo
3,David,,1000USD,Hetero
Given the following class:
package com.example.model;
import java.util.Collection;
import java.util.Set;
import org.neo4j.graphdb.Direction;
import org.neo4j.helpers.collection.IteratorUtil;
import org.springframework.data.neo4j.annotation.Indexed;
import org.springframework.data.neo4j.annotation.NodeEntity;
import org.springframework.data.neo4j.annotation.RelatedTo;
import org.springframework.data.neo4j.annotation.RelatedToVia;
import org.springframework.security.core.GrantedAuthority;
#NodeEntity
public class User {
private static final String SALT = "cewuiqwzie";
public static final String FRIEND = "FRIEND";
public static final String RATED = "RATED";
#Indexed
String login;
String name;
String password;
String info;
private Roles[] roles;
public User() {
}
public User(String login, String name, String password, Roles... roles) {
this.login = login;
this.name = name;
this.password = encode(password);
this.roles = roles;
}
private String encode(String password) {
return "";
// return new Md5PasswordEncoder().encodePassword(password, SALT);
}
#RelatedToVia(elementClass = Rating.class, type = RATED)
Iterable<Rating> ratings;
#RelatedTo(elementClass = Movie.class, type = RATED)
Set<Movie> favorites;
#RelatedTo(elementClass = User.class, type = FRIEND, direction = Direction.BOTH)
Set<User> friends;
public void addFriend(User friend) {
this.friends.add(friend);
}
public Rating rate(Movie movie, int stars, String comment) {
return relateTo(movie, Rating.class, RATED).rate(stars, comment);
}
public Collection<Rating> getRatings() {
return IteratorUtil.asCollection(ratings);
}
#Override
public String toString() {
return String.format("%s (%s)", name, login);
}
public String getName() {
return name;
}
public Set<User> getFriends() {
return friends;
}
public Roles[] getRole() {
return roles;
}
public String getLogin() {
return login;
}
public String getPassword() {
return password;
}
public String getInfo() {
return info;
}
public void setInfo(String info) {
this.info = info;
}
public void updatePassword(String old, String newPass1, String newPass2) {
if (!password.equals(encode(old)))
throw new IllegalArgumentException("Existing Password invalid");
if (!newPass1.equals(newPass2))
throw new IllegalArgumentException("New Passwords don't match");
this.password = encode(newPass1);
}
public void setName(String name) {
this.name = name;
}
public boolean isFriend(User other) {
return other != null && getFriends().contains(other);
}
public enum Roles implements GrantedAuthority {
ROLE_USER, ROLE_ADMIN;
#Override
public String getAuthority() {
return name();
}
}
}
I get a compilation exception here:
public Rating rate(Movie movie, int stars, String comment) {
return relateTo(movie, Rating.class, RATED).rate(stars, comment);
}
Following the tutorial here. Any insight as to where this function resides is appreciated.
You're trying to use the advanced mapping mode. See the reference manual for more information. You'll need to set up AspectJ support in your IDE. Methods are woven into your entity classes at compile time.