-1
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.

Community
  • 1
  • 1
ritesh
  • 907
  • 3
  • 11
  • 31
  • Will be interesting to see how you are initializing your targetCustomer before passing to BeanUtils. I assume you are returning targetCustomer from getCustomer(int) method. By any change, you are returning the "same" instance of target Customer each time. – Optional Jul 09 '13 at 06:02
  • 1
    Where is the immutable object? I don't see any final variables. – tom Jul 09 '13 at 06:05
  • @Optional: I am fetching data from Database to initialize targetCustomer before passing to Bean Utils. – ritesh Jul 09 '13 at 06:14
  • @tom: as per my knowledge, which is still small, I can not make CustomerDTO class final with spring, I could only have made few CustomerDAO methods final. I would appreciate if you could refer/tell me way to do so in Spring. – ritesh Jul 09 '13 at 06:17
  • Downvoter: Please share your comment or answer the question. – ritesh Jul 09 '13 at 07:33
  • @ritesh please share ur code to initialize targetCustomer. I guess you are "reusing" the same object and hence the problem – Optional Jul 10 '13 at 10:09
  • @Optional: I can not share requested piece of code for multiple reasons and believe me it has almost no effect on results of test cases. I have already solve the problem http://stackoverflow.com/a/17545377/1544069. Thanks :) – ritesh Jul 10 '13 at 10:27

2 Answers2

1

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.

Uwe Plonus
  • 9,803
  • 4
  • 41
  • 48
  • Could you please explain test case : "With Immutable Objects"? – ritesh Jul 09 '13 at 06:24
  • 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: http://stackoverflow.com/a/2156367/1544069. I would appreciate if you could tell me right tools as well. – ritesh Jul 09 '13 at 06:38
  • 1
    @ritesh Why do you think you have immutable objects? I don't see any immutability in your design. – Uwe Plonus Jul 09 '13 at 06:40
  • @ritesh Found my error and corrected my answer. `BeanUtils.copyProperties()` is suitable for this use case. But you still try to use the Spring context for anything that it is not designed for. – Uwe Plonus Jul 09 '13 at 06:41
  • I am really thankful to you for answering this question. I think Immutable object is creating some confusion. My intention is to make this method `CustomerDTO getCustomer(int customerId)` return Immutable object which would be CustomerDTO,which I am trying to with BeanUtils, and then I am adding these objects into the list in method `List getCustomerList(List customerIds)`. hope this adds some clarity – ritesh Jul 09 '13 at 06:45
  • I think I am using spring context only in `origCustomer` which would be needed for `BeanUtils.copyProperty()` otherweise it will throw error. By instantiating beans through spring context, I am initializing them to default values. – ritesh Jul 09 '13 at 06:49
  • Do you still think that I am mixing Spring bean with java bean? I understand the singleton concept but then why is it not reflecting in test case results? – ritesh Jul 09 '13 at 08:02
0
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;

ritesh
  • 907
  • 3
  • 11
  • 31