Adding objects (copied through Defensive copying using BeanUtils) in ArrayList giving stale data: Spring 3

StackOverflow https://stackoverflow.com/questions/17540883

Question

public class CustomerDTO {
    private int customerId;
    private String customerName;
    private String customerAddress;

    public int getCustomerId() {
        return customerId;
    }
    public void setCustomerId(int customerId) {
        this.customerId = customerId;
    }
    public String getCustomerName() {
        return customerName;
    }
    public void setCustomerName(String customerName) {
        this.customerName = customerName;
    }
    public String getCustomerAddress() {
        return customerAddress;
    }
    public void setCustomerAddress(String customerAddress) {
        this.customerAddress = customerAddress;
    }
}

CustomerDAO class:

import java.util.ArrayList;
import java.util.List;
import java.util.Collections;

public final class CustomerDAO {
    private CustomerDTO customer;

    public void setCustomer(CustomerDTO customer) {
        this.customer = customer;
    }

    //Trying to get copy of object with BeanUtils
    public final CustomerDTO getCustomer(int customerId){
        CustomerDTO origCustomer = _springContext.getBean(CustomerDTO.class);
        CustomerDTO targetCustomer=null;
        if("you get customer based on customer id") then "targetCustomer got initialized";
        BeanUtils.copyProperties(targetCustomer, origCustomer);//spring BeanUtils
    }

    //Trying to add object returned by above method into the list
    public final List<CustomerDTO> getCustomerList(List<Integer> customerIds){
        List<CustomerDTO> customerList = new ArrayList<CustomerDTO>();
        for(Integer id:customerIds){
            CustomerDTO customer = getCustomer(id);
            System.out.println("correct output: "+customer.getCustomerId());//getting correct output here
            customerList.add(customer);//Trying to add copied object in list
        }
        for(CustomerDTO customer: customerList){
            System.out.println("wrong output: "+customer.getCustomerId());//getting wrong output here
        }
        return Collections.unmodifiableList(customerList);
    }
}

In CustomerDTO getCustomer(int customerId) method, I am trying to return copy of CustomerDTO object by using Spring BeanUtils.copyProperties(targetCustomer, origCustomer);, But when I am adding these copied objects in list in method List<CustomerDTO> getCustomerList(List<Integer> customerIds) then I am getting strange behavior as mentioned in the comments. If I am removing BeanUtils.copyProperties(targetCustomer, origCustomer); then behavior is correct.

Test case:

getCustomerList with customerIds =[1,2,3,4]

With copied objects: BeanUtils.copyProperties(targetCustomer, origCustomer);//spring BeanUtils

correct output: 1
correct output: 2
correct output: 3
correct output: 4
wrong output: 4
wrong output: 4
wrong output: 4
wrong output: 4

Without copied objects: BeanUtils.copyProperties(targetCustomer, origCustomer);//spring BeanUtils

correct output: 1
correct output: 2
correct output: 3
correct output: 4
wrong output: 1
wrong output: 2
wrong output: 3
wrong output: 4

Could someone please explain me what is wrong or possible explanation for this behavior?

Updated: Purpose of using BeanUtils:

I am trying to use defensive copy of the mutable object before returning the CustomerDTO object from the method getCustomer(). So I try to use shallow cloning following this post.

update: Removed the word Immutability as it was wrong to use.

Was it helpful?

Solution 2

wrong output: 4
wrong output: 4
wrong output: 4
wrong output: 4

This could happen if the list is containing same object, then Why is list containing same object and how could following work?

correct output: 1
correct output: 2
correct output: 3
correct output: 4

origCustomer is containing reference to say CustomerDTO@60bc92, which is singleton maintained by spring, So it would always have same reference. Reference for targetCustomer will change. But BeanUtils.copyProperties(targetCustomer, origCustomer); will copy the properties of targetCustomer to origCustomer means CustomerDTO@60bc92.

for(Integer id:customerIds){
            CustomerDTO customer = getCustomer(id);
            System.out.println("correct output: "+customer.getCustomerId());//getting correct output here
            customerList.add(customer);//Trying to add copied object in list
        }

for(customer ids 1 to 4){
       customer will get reference CustomerDTO@60bc92 and will be updated based on customer ids
       so it is printing correct values 
       but it is adding same reference CustomerDTO@60bc92 to the list
}

 for(CustomerDTO customer: customerList){
            System.out.println("wrong output: "+customer.getCustomerId());//getting wrong output here
        }

for(all customer object in list which is same object reference and having latest value means 4){
      it is printing wrong value as 4
}

Now why origCustomer is being created from Spring context, like

CustomerDTO origCustomer = _springContext.getBean(CustomerDTO.class);

Because BeanUtils from spring needs default initialized spring bean.

Solution of this problem:

CustomerDTO origCustomer = new CustomerDTO();

and using BeanUtils from org.apache.commons.beanutils.BeanUtils;

OTHER TIPS

You're using the wrong tools.

Your problem is that you mixed up Spring beans with Java beans.

A Spring bean is a singleton and therefore you only have one CustomerDTO in your Spring context. The Spring context is not a replacement for a real DAO.

Either use aMap or a database in your DAO and don't try to use the Spring context for data storage and retrieval operations.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top