Add all elements to the another List in java? - java

I am trying to implement "add to cart" concept like any e-commerce website on the basis of "productId". when i am calling this controller, it's add only last element which user added to the list instead of all product list.
#RequestMapping("/addcart/{list.productId}")
public String addCart(#PathVariable("list.productId") Integer productId, Model m, HttpSession session) {
List<Product> cartlist = productDao.findById(productId);
List<Product> useradd = new ArrayList<>();
for (Product e : cartlist) {
useradded.add(e);
}
session.setAttribute("sessioncartview", useradded);
return "redirect:/";
}
i found only one product which was last added, not all product list. in "useradded". i want to add all elements in the list i.e. "useradded" object and after that bind with session. how can i do that ?

Because you are creating a new useradded list every time when this method is called.
Instead of doing
List<Product> useradd = new ArrayList<>();
you can get the useradd from the session and only create a new instance if it is not there.
List<Product> useradd = session.get("sessioncartview");
if (useradd == null) {
useradd = new ArrayList<>();
}

Related

How can I to refactor this code and decouple method?

I have set of entities(templates)
I need to clone full this set and create same set with new Ids.
I have 3 methods like this(Entity One is User):
private Map<String, String> createUsers() {
Map<String, String> userIds = new HashMap<>();
Iterator<User> users = userService.findAllUsers();
while (users.hasNext()) {
User user = users.next();
String oldId = user.getId();
user.setId(generateNewId());
user.setName(generateNewName());
userService.saveUser(user);
userIds.put(oldId, user.getId());
}
return userIds;
}
And two similar methods(Entity two is Person and Entity Three is Book). In each method, I create new entity and store old and new IDS. After that, I clone Orders and relink old id and new id. I do it like this:
if (userIds.containsKey(order.getUserId())) {
order.setUserId(userIds.get(order.getUserId()));
}
if (personIds.containsKey(order.getPersonId())) {
order.setPersonId(personIds.get(order.getPersonId()));
}
This structure is ugly and I want to refactor it. But I have not ideas.

How to figure out what object is in a abstract list?

I have an abstract class called sessions. Lectures and tutorials extend sessions. Then I have a class called enrollment which holds a list of sessions (Lectures & tutorials). How can I loop through the session list in Enrolment and return a list of Lectures only from the session list?
My next question is should I instead store 2 lists. One list of Lectures and one list of Tutorials, instead of 1 session list? This is because the sessions list is useless to me and I have to loop through it each time to get information about lectures and tutorials. Is there a way I am missing to get all the lectures objects? I am new to java.
public class Enrolment {
private List<Session> sessions;
public Enrolment() {
this.sessions = new ArrayList<>();
}
public addSession(Session session) {
this.sessions.add(session);
}
}
public class Session {
private int time;
public Session(int time) {
this.time = time;
}
}
public class Lecture extends Session {
private String lecturer;
public Lecture(int time, String lecturer) {
super(time);
this.lecturer = lecturer;
}
}
public class Tutorial extends Session {
private String tutor;
private int tutorScore;
public Tutorial(int time, String tutor, int tutorScore) {
super(time);
this.tutor = tutor;
this.tutorScore = tutorScore;
}
}
public class test {
public static void main(String[] args) {
Enrolment newEnrolment = new Enrolment();
Lecture morningLec = new Lecture(900, "Dr. Mike");
newEnrolment.addSession(morningLec);
Tutorial afternoonTut = new Tutorial(1400, "John Smith", 3);
newEnrolment.addSession(afternoonTut);
Lecture middayLec = new Lecture(1200, "Mr. Micheals");
newEnrolment.addSession(middayLec);
Tutorial NightTut = new Tutorial(1900, "Harry Pauls", 4);
newEnrolment.addSession(NightTut);
}
}
Stream the sessions list and use instanceof to filter the Lectures type objects
List<Lecture> l = sessions.stream()
.filter(Lecture.class::isInstance)
.map(Lecture.class::cast)
.collect(Collectors.toList());
By using for loop use two different lists for each type
List<Lecture> l = new ArrayList<>();
List<Tutorial> t = new ArrayList<>();
for (Session s : sessions) {
if (s instanceof Lecture) {
l.add((Lecture) s);
}
else if(s instanceof Tutorial) {
t.add((Tutorial) s);
}
}
Maybe you should store in two lists, just like:
public class Enrolment {
private List<Lecture> lectures;
private List<Tutorial> tutorials;
public Enrolment() {
this.lectures = new ArrayList<>();
this.tutorials = new ArrayList<>();
}
public void addSession(Session session) {
if (session instanceof Lecture) {
lectures.add((Lecture) session);
} else if (session instanceof Tutorial) {
tutorials.add((Tutorial) session);
}
}
public List<Lecture> getLectures() {
return lectures;
}
public List<Tutorial> getTutorials() {
return tutorials;
}
public List<Session> getAllSessions() {
ArrayList<Session> sessions = new ArrayList<>(lectures);
sessions.addAll(tutorials);
return sessions;
}
}
Is that what you need?
My next question is should I instead store 2 lists. One list of
Lectures and one list of Tutorials, instead of 1 session list? This is
because the sessions list is useless to me and I have to loop through
it each time to get information about lectures and tutorials. Is there
a way I am missing to get all the lectures objects?
You answered yourself to your problem.
When you start to write too complex/boiler plate code to make things that should be simple such as iterating on a list of objects that you have just added, it is a sign that you should step back and redesign the thing.
By introducing Enrolment.addSession(Session session),
you introduced an undesirable abstraction :
public class Enrolment {
private List<Session> sessions;
public Enrolment() {
this.sessions = new ArrayList<>();
}
public addSession(Session session) {
this.sessions.add(session);
}
}
You don't want to handle uniformally Lecture and Tutorial from the Enrolment point of view, so just don't merge them in the same List only because these rely on the same interface (Session).
Abstraction has to be used when it is required and not systematically because that is possible.
Don't you add all objects in a List of Object because all is Object ? No.
Instead of, create this distinction both from the API method and from its implementation :
public class Enrolment {
private List<Conference> conferences = new ArrayList<>();
private List<Tutorial> tutorials = new ArrayList<>();
public addConference(Conference conference) {
this.conferences.add(conference);
}
public addTutorial(Tutorial tutorial) {
this.tutorials.add(tutorial);
}
}
And use it :
Lecture morningLec = new Lecture(900, "Dr. Mike");
newEnrolment.addLecture(morningLec);
Tutorial afternoonTut = new Tutorial(1400, "John Smith", 3);
newEnrolment.addTutorial(afternoonTut);
Note that you could have a scenario where you need to manipulate uniformally Tutorial and Lecture for some processings but that for others you want to distinguish them.
In this case, you have some common ways :
instanceOf : easy to use but also easy to make a code brittle. For example, later you could add a new subclass in the Session hierarchy and without be aware of it, instances of this subclass could be included or excluded in some processing without that the compiler warns you.
provide a abstract method that returns a boolean or an enum to convey the nature of the object (ex: isLecture()). More robust than instanceOf since the compiler constraints you to override the method but it may also lead to error prone code if multiple subclasses are added and that the filters are not only on Lecture but Lecture and another type. So I would favor this way while the filtering condition stays simple.
define three lists : one for lectures, another for conferences and another that contains all of these that should be handled uniformally. More complex way but more robust way too. I would favor it only for cases with complex/changing filtering conditions.
List<Lecture> l = newEnrolment.getSessions()
.stream()
.filter(s-> s.getClass().equals(Lecture.class))
.map(session -> (Lecture) session)
.collect(Collectors.toList());
!!! Don't use typeof
Quoting from your question,
This is because the sessions list is useless to me.
So, this is probably not the right place to have the list(?).
My preference would be to have
public interface Enrolment {
public abstract addSession(Session session);
public abstract getSessions();
}
And List<LectureEnrolment> and List<TutorialEnrolment> must be in their respective classes.(I have renamed Lecture to LectureEnrolment and Tutorial to TutorialEnrolment)
main() must have something like,
Enrolment lectureEnrolment= new LectureEnrolment()
Enrolment tutorialEnrolement = new TutorialEnrolment()
call the respective addSession() or getSession() depending on requirement.
change private List<Session> sessions; to public List<Session> sessions; in class Enrolment
public static void main(String[] args) {
....
var lecturesAndTutorials = newEnrolment.sessions.where(x => x.getType() == typeof(Lecture) || x.getType() == typeof(Tutorial));
....
}

Recursive method, load children. Java

I have an entity that has an attribute "father" is a reference to his father. (Like this in the database)
Now I need to create a tree in view, and I have to carry the children recursively.
I have made the method below, but I doubled the children. And not further if the (optimal) correct way to do this process.
Can somebody help me.
Thank you.
#Transactional(readOnly = true)
public Page<CategoriaDTO> findAll(Pageable pageable) {
log.debug("Request to get all Categorias");
Page<Categoria> result = categoriaRepository.findByPadreIsNull(pageable);
List<CategoriaDTO> categoriaDtos = new ArrayList<>();
for (Categoria categoriaAux : result) {
CategoriaDTO categoriaDto = categoriaMapper.categoriaToCategoriaDTO(categoriaAux);
categoriaDto.setHijos(categoriaMapper.categoriasToCategoriaDTOs(categoriaRepository.findByPadre(categoriaAux)));
hijos(categoriaDto.getHijos(),categoriaDto.getId());
categoriaDtos.add(categoriaDto);
}
return new PageImpl<CategoriaDTO>(categoriaDtos);
}
private void hijos(List<CategoriaDTO> hijos,Long padreId){
Categoria categoriaPadre = categoriaRepository.findOne(padreId);
if(! CollectionUtils.isEmpty(hijos)){
for (CategoriaDTO hijo : hijos) {
hijo.setHijos(categoriaMapper.categoriasToCategoriaDTOs(categoriaRepository.findByPadre(categoriaPadre)));
hijos(hijo.getHijos(),hijo.getId());
}
}
}
As I understand, in your entity you have a reference to the same entity.
So you could start the leaf and go up in the tree. Call the function recursively until the Entity has null parent(that means you reached the root). You also add the Entities to a list.
LinkedList<Category> list = new LinkedList<>();
public void getChildren(Category category) {
list.add(category);
if(category.getParent() == null)
return;
getChildren(category.getParent());
}
This is just an example, post your Entity for more details

put in hashmap using two lists and database

I have two classes, User and Customer, using hibernate, I have mapped these tables, now I want to retrieve the data from the database, where I can put the values in hashmap such that for each user, if a particular customer exists in the mapping table, then the key of map is set as the customer name, and value to true or false, depending upon the mapping table.
I have retrieved both the lists:
static List<User> listUsers = new ArrayList<User>();
static List<Customer> listCustomers = new ArrayList<Customer>();
List<UserTO> list = new ArrayList<UserTO>();
public static List<Customer> getListOfCustomers() {
HibernateUtil.openSession();
Session session = HibernateUtil.getSession();
Transaction tx = null;
try {
tx = session.getTransaction();
tx.begin();
listCustomers = session.createQuery("from Customer").list();
tx.commit();
} catch (Exception e) {
if (tx != null) {
tx.rollback();
}
e.printStackTrace();
} finally {
session.close();
}
return listCustomers;
}
(similarly list of users)
in UserTO class, I have:
public class UserTO implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue
private Long id;
private String userId;
private Map<String, Boolean> map = new HashMap<String, Boolean>();
(getter and setter)
I tried doing this:
public static void execute() {
getListOfUsers();
getListOfCustomers();
for (User user : listUsers) {
UserTO u = new UserTO();
Map<String, Boolean> map = new HashMap<>();
for (Customer customer : listCustomers) {
if (customer.getCompanyName() == user.getCustomers(customer)) {
map.put(customer.getCompanyName(), true);
} else {
map.put(customer.getCompanyName(), false);
}
}
user.getUserId();
u.setUserId(user.getUserId());
u.setMap(map);
listUsers.add(user);
}
}
which gives me Concurrent Modification Exception
I don't know where I am doing wrong, and what should I do next.
you are adding user to listUsers when you are iterating over this listuser. This results in the given exception.
Use list.add(u);
Reason for ConcurrentModificationException is you are trying to add to the list at the same time when you are iterating like:
for (User user : listUsers) {
....
listUsers.add(user);
One way to solve this would be to create a temporary list and keep adding to that list and after your for loop, use addAll method on listUsers to add all your users that you added in the loop.
Note: Inorder to select the data, you don't need transaction as select wont do any side effect to your table.
What you are trying to do is that you are getting a User object from the list, and then again adding it to the list. It wont work for the following reasons:
You are iterating the list and adding in the same loop which is not allowed and throws ConcurrentModificationException.
Also you are adding in every iteration. Which means that the list will grow with every iteration and your loop will never end. First you should remove the object and then again add it in the same place.
Solution:
public static void execute() {
getListOfUsers();
getListOfCustomers();
for (int i=0;i<listUsers.size();i++) {
User user = listUsers.remove(i);
UserTO u = new UserTO();
Map<String, Boolean> map = new HashMap<>();
for (Customer customer : listCustomers) {
if (customer.getCompanyName() == user.getCustomers(customer)) {
map.put(customer.getCompanyName(), true);
} else {
map.put(customer.getCompanyName(), false);
}
}
user.getUserId();
u.setUserId(user.getUserId());
u.setMap(map);
listUsers.add(i,user);
}
}
P.S. - But still I don't get that why there is a need to add an object which already exists in the list without any change.
You are getting concurrent modification exception as HashMap is not thread safe. Use concurrentHashMap instead. Thanks hope it helps.

Spring mvc,java.lang.NullPointerException while adding an item in a set of an entity

I have two entities "billable" and item. There is bidirectional oneToMany mapping between both.
When I am trying to add set of item to billable. It is showing:
"java.lang.NullPointerException"
How can I add set of item to billable properly.
I am trying to add item to billable like this. Another entity user has set of items also.
Set<Item> s = (Set)user.getItem();
for(Item i:s){
Set<Item> items = new HashSet<Item>();
System.out.println(i.getItemName());
Item myItem = (Item)i;
bill.getItem().add(myItem);
}
Here is my controller
#RequestMapping(value="/checkOut",method = RequestMethod.POST)
public String checkOut(#RequestParam("id")String userName){
billable bill = new billable();
bill.setBillableName(rName);
bill.setBillableAddress(bAddress);
User user = userService.getuserByName(userName);
bill.setUser(user);
Set<Item> s = (Set)user.getItem();
for(Item i:s){
Set<Item> items = new HashSet<Item>();
System.out.println(i.getItemName());
Item myItem = (Item)i;
bill.getItem().add(myItem);
}
I suspect your Billable object has a field like:
private Set item;
There are two options here:
Option 1, in your Billable object, on the getItem() method, add a null check:
public Set<Item> getItem() {
if (item == null) {
item = new HashSet<>();
}
return item;
}
This is a fairly common approach.
Option two, change your controller you set the items, not the item:
#RequestMapping(value="/checkOut",method = RequestMethod.POST)
public String checkOut(#RequestParam("id")String userName){
billable bill = new billable();
bill.setBillableName(rName);
bill.setBillableAddress(bAddress);
User user = userService.getuserByName(userName);
bill.setUser(user);
Set<Item> s = (Set)user.getItem();
Set<Item> items = new HashSet<Item>();
for(Item i:s){
System.out.println(i.getItemName());
Item myItem = (Item)i;
//I'm assuming your gonna actually do something here, not just loop for fun
items.add(i);
}
bill.setItem(items);

Categories

Resources