-1

I take like this:

 Collection<TaskComment> commentsCollection = task.getComments();
 ArrayList<TaskComment> comments = new ArrayList<>(commentsCollection);

       for(TaskComment cmnt : comments){

                cmnt.setUser(commentUser.getLogin());
                cmnt.setCreatedAtString(cmnt.getCreatedAt().format(DateTimeFormatter.ofPattern(Constants.DATE_TIME_FORMAT)));
            }

Here I take comments and put them into a collection, then into an arraylist. Then I manipulate the comments with DTO class methods.

But when I change cmnt, the comments from task.getcomments changes.

I think this code is enough but I can give more code if you want. Why does it change? It was supposed not to change because I moved it to collection then to array?

I don't do this:

repository.save(task);

after I manipulate the comment, so it must not save to database? So why does

task.getComments();

return changed data? I did not save to database?

SQB
  • 3,926
  • 2
  • 28
  • 49
mark
  • 727
  • 3
  • 14
  • 35
  • I dont do this: repository.save(task); after i manipulated, so it must not save to database? So why does task.getComments(); brings changed data? I did not save to database? – mark Oct 19 '16 at 10:23

4 Answers4

2

It's because you're still looking at the same TaskComment objects.

References to a specific comment may be in two collections, commentsCollection and comments, but it's only one object. It doesn't matter how you get at the object, if you manipulate it, it changes.


Imagine your objects, in this case comments, as boxes. You tie a red string to each box and give the strings to Alice to hold. Then you tie a blue string to each box and give those strings to Bob to hold.
Now let's say Bob pulls on a string and gets a box. He opens the box, puts a marble in it and shoves the box back in its place.
Now Alice pulls on the string for that box and gets the box. If she opens it, she'll find a marble in it.


What happens if you call task.getComments(); again, depends on the implementation. If you didn't save to the database and if that method gets them from the database each and every time, you shouldn't see any changes in those comments. It's as if you get a new set of boxes for Alice.

However, what's far more likely is that when you load a Task from the database, it loads the associated comments with it, adding them as a property of the Task. Then, with each call to get the comments, you don't get them from the database, you get them from the Task object. And those comments are the one both Alice and Bob have strings tied to.

SQB
  • 3,926
  • 2
  • 28
  • 49
  • 1
    Can we say, its a reference to object and then the manipulation is done on the object itself. ? – voucher_wolves Oct 19 '16 at 09:17
  • So, how can i get over it? I need to pass to front end different comments but i cant change it. – mark Oct 19 '16 at 10:14
  • I dont do this: repository.save(task); after i manipulated, so it must not save to database? So why does task.getComments(); brings changed data? I did not save to database? – mark Oct 19 '16 at 10:24
  • @SQB , so I am very much confused if Java is pass by value or reference, because everyone says, its pass by value :) – voucher_wolves Oct 19 '16 at 11:33
1

In your example, you are creating only 1 object task.getComments(); which is being referred by both commentsCollection and comments reference variables.

Therefore, changing in object will be reflected to both reference variables.

Collection<TaskComment> commentsCollection = task.getComments();
ArrayList<TaskComment> comments = new ArrayList();
for(TaskComment cmnt : commentsCollection ){
    comments.add(cmnt.clone());
 }

Override clone method in TaskComment class as follows:

public Object clone() {
    //deep copy
    TaskComment newObject = new TaskComment();
    //Now copy each property of original object to the new object.
    //e.g. newObject.setProperty(this.getProperty()); 
    return newObject;
  }
gschambial
  • 1,383
  • 2
  • 11
  • 22
  • So, how can i get over it? I need to pass to front end different comments but i cant change it. – mark Oct 19 '16 at 10:14
  • I dont do this: repository.save(task); after i manipulated, so it must not save to database? So why does task.getComments(); brings changed data? I did not save to database? – mark Oct 19 '16 at 10:24
  • @mark You need to DEEP COPY your `commentsCollection` list into `comments` list. – gschambial Oct 19 '16 at 10:25
1

This is happening because by executing below line you will get a collection of references which holds the actual objects

Collection<TaskComment> commentsCollection = task.getComments();

like

commentsCollection
  --> 0th element in commentsCollection --> (TaskComment object 1)
  --> 1st element in commentsCollection --> (TaskComment object 2)
  --> 2nd element in commentsCollection --> (TaskComment object 3)

Now when you will copy it in comments ArrayList

ArrayList<TaskComment> comments = new ArrayList<>(commentsCollection);

but still it will be like

comments
  --> 0th element in comments --> (TaskComment object 1)
  --> 1st element in comments --> (TaskComment object 2)
  --> 2nd element in comments --> (TaskComment object 3)

And now when you try to access your objects you are actually doing the changes in TaskComment objects (1, 2 and 3), That's why task.getcomments() getting changed.

Naresh Joshi
  • 4,188
  • 35
  • 45
  • So, how can i get over it? I need to pass to front end different comments but i cant change it. – mark Oct 19 '16 at 10:14
  • 1
    If you need it, so you send it to front end try to create a new response class TaskCommentResponse (by using same TaskComment) and then copy every TaskComment into new one or use clone – Naresh Joshi Oct 19 '16 at 10:22
  • I dont do this: repository.save(task); after i manipulated, so it must not save to database? So why does task.getComments(); brings changed data? I did not save to database? – mark Oct 19 '16 at 10:24
  • Maybe you are using @Transactional which save the changed objects automatically to DB. – Naresh Joshi Oct 19 '16 at 10:47
  • No, it is not saved to db . for next calling there, unchanged values come again. task.getcomments only changes for temporary but i dont understand it. – mark Oct 19 '16 at 10:57
  • I think you are saying that values returned by the task.getcomments() giving the changed TaskComment objects but if you fetch them again from DB, the task.getcomments() returns same old TaskComment objects. If so, then I like to tell you that the task.getcomments() giving the changed TaskComment objects because the changes you are doing in the for are actually changing your objects in heap. And task.getComments() and commentsCollection and comments pointing to the same objects. So If you change a TaskComment object from any of these collections other will reflect those changes. – Naresh Joshi Oct 19 '16 at 11:28
1

In your code, the actual object i.e commentsCollection reference will be assigned to comments collection, and after that, you are iterating this collection, and while iterating this new collection object i.e. comments, you are modifying actual reference i.e. commentsCollection.

In Java, you can create one object and reference it by multiple references which are indirectly holding a pointer to the object. Calling a mutator method on any reference will effectively modify the sole object, thus updating all other references.

Naresh Joshi
  • 4,188
  • 35
  • 45