2013-07-16 64 views
3

在我最近的項目中,我使用jQuery Grid,當用戶點擊按鈕時生成動態網格。爲什麼多個DTO會更改會話映射?

在服務器端數據通過使用Session來操縱。

首先,我得到Session對象並將該對象轉換爲gatepassDTO

然後,我創建一個本地對象,並將屬性從舊對象複製到Map

之後,我創建futureDTO對象和複製屬性從gatepassDTOfutureDTO。如果我更改futureDTO中的任何內容,它將影響包含對象的地圖。

爲什麼會發生這種情況?

public String addOnemoreGatepass() { 

     log.info("----------------Entering method addOnemoreGatepass------------"); 
     try { 
      Object map = session.get("gatepassMap"); 

      GatepassDTO gatepassDTO = new GatepassDTO(); 
      gatepassDTO=(GatepassDTO)session.get("gatepassDTO"); 
      if(map!=null){ 

       //gatepassMap=Collections.synchronizedMap((HashMap)map); 
      } 
      if(truckNo!=null){ 
       gatepassDTO.setTruckNo(truckNo); 
      } 

        if(gpDirect!=null){ 
       GatepassDTO tempDTO=new GatepassDTO(); 
       copyProperty(tempDTO,gatepassDTO); 
      /* HashMap<String,GatepassDTO> maps=null; 
       if(gatepassNo.equals("1")){ 
        maps=new HashMap<String, GatepassDTO>(); 
       local.saveMap(getRequest().getSession().getId(),maps); 
       } 
       maps=local.loadMap(getRequest().getSession().getId()); 
       maps.put(gatepassNo, tempDTO);*/ 
       putCachedObject("SINGLEGATEPASSCACHE", gatepassNo, tempDTO); 
       gatepassMap.put(gatepassNo, tempDTO); 

       //local.saveMap(getRequest().getSession().getId(),maps); 
       session.put("documentType", documentType); 
       session.put("gatepassMap", gatepassMap); 
       return SUCCESS; 
      } 
      else{ 
       GatepassDTO tempDTO=new GatepassDTO(); 
       copyProperty(tempDTO,gatepassDTO); 
       /*HashMap<String,GatepassDTO> maps=null; 
       if(gatepassNo.equals("1")){ 
        maps=new HashMap<String, GatepassDTO>(); 
       local.saveMap(getRequest().getSession().getId(),maps); 
       } 
       maps=local.loadMap(getRequest().getSession().getId()); 
       maps.put(gatepassNo, tempDTO);*/ 
       putCachedObject("SINGLEGATEPASSCACHE", gatepassNo, tempDTO); 
       gatepassMap.put(gatepassNo, tempDTO); 

       //local.saveMap(getRequest().getSession().getId(),maps); 
       session.put("documentType", documentType); 
       session.put("gatepassMap", gatepassMap); 

      } 
      GatepassDTO futureDTO=new GatepassDTO(); 
      copyProperty(futureDTO,gatepassDTO); 

      DocumentDTO documentDTO =futureDTO.getDocumentDTO(); 
      List<GatepassGoodsDTO> goodsList=documentDTO.getGatepassGoodsList(); 
      int i=0; 
      for(GatepassGoodsDTO goodsDTO:goodsList){ 
       if(goodsDTO.getRemovalType()!=null&&(goodsDTO.getRemovalType().equals("Quantity")||goodsDTO.getRemovalType().equals("Weight"))){ 
       goodsDTO.setPrevRemovalType(goodsDTO.getRemovalType()); 
       goodsDTO.setPrevGPQuantity((goodsDTO.getRemovalQuantity()!=null?goodsDTO.getRemovalQuantity():0)); 
       goodsDTO.setPrevGPWeight((goodsDTO.getRemovalWeight()!=null?goodsDTO.getRemovalWeight():0)); 
       goodsDTO.setBalanceQuantity(goodsDTO.getBalanceQuantity()-goodsDTO.getRemovalQuantity()); 
       goodsDTO.setBalanceWeight(goodsDTO.getBalanceWeight()-goodsDTO.getRemovalWeight()); 
       goodsDTO.getVehicleDetailsList().clear(); 
       goodsDTO.setVehicleDetailsList(goodsDTO.getDeletedVehicleDetailsList()); 
       goodsDTO.setDeletedVehicleDetailsList(new ArrayList<GatepassVehicleDTO>()); 
       goodsDTO.setRemovalType(""); 
       goodsDTO.setRemovalQuantity(0); 
       goodsList.set(i, goodsDTO);} 
       else{ 
        goodsList.set(i, goodsDTO); 
       } 
       i++; 
      } 
      documentDTO.setGatepassGoodsList(goodsList); 
      documentDTO.setContainerList(deletedContainerModel); 
      futureDTO.setDocumentDTO(documentDTO); 
      futureDTO.setTruckModel(new ArrayList<GatepassTruckDTO>()); 
      session.put("gatepassDTO",futureDTO); 
      // setDocumentModel(null); 
      // setGridModel(null); 
      deletedVehicleModel.clear(); 
      deletedContainerModel.clear(); 
      // manifestNo=null; 



     } catch (Exception e) { 
      log.info(e.getMessage()); 
     } 
     log.info("---------------Ending method addOnemoreGatepass----------------"); 
     return SUCCESS; 
    } 


private void copyProperty(GatepassDTO tempDTO,GatepassDTO gatepassDTO){`enter code here` 
     tempDTO.setDocumentDTO(gatepassDTO.getDocumentDTO()); 
     tempDTO.setTruckNo(gatepassDTO.getTruckNo()); 
    } 

爲什麼會出現此問題? 這是Java核心問題還是Struts2 JSON問題?

+0

問題是什麼?你的意思是,如果你改變了futureDTO的「DocumentDTO」,它也會影響會話中的對象? – mael

+0

是的?如果IAM改變未來的dtoDocument數據集,它也會改變Hasmap包含tempDTO.I在覈心Java中嘗試同樣的事情,它會正常工作,但在我的項目 – user1965582

回答

0

當你從一個Map中獲得一個對象時,你沒有得到這個對象的副本,你得到了該對象的一個​​引用。這意味着如果你改變了對象的屬性,hashmap中的對象「in」也會改變它的屬性(因爲它是同一個對象)。

這是發生了什麼代碼:

  1. 你到會話對象「getpassDTO」
  2. 參考擾得該對象的屬性(對象的copyProperty副本引用參考文獻,它不克隆你的對象)
  3. 你正在修改這些引用的屬性。但是你的「getPassDTO」會話對象仍然引用相同的屬性。
1

您正在處理參考文獻(認爲它們爲指針)。

當你從會話地圖,你得到它的引用(甚至是地圖是隻包含引用,而不是真正的對象)

gatepassDTO = (GatepassDTO)session.get("gatepassDTO"); 

的對象,然後你實例tempDTO,並指定參考gatepassDTO.getDocumentDTO()的(它是引用本身)tempDTO

GatepassDTO tempDTO = new GatepassDTO(); 
copyProperty(tempDTO,gatepassDTO); 
// that inside inside copyProperty does: 
tempDTO.setDocumentDTO(gatepassDTO.getDocumentDTO()); 

然後你實例futureDTO,並分配AGAIN gatepassDTO.getDocumentDTO()的參考:

GatepassDTO futureDTO = new GatepassDTO(); 
copyProperty(futureDTO,gatepassDTO); 
// that inside inside copyProperty does: 
futureDTO.setDocumentDTO(gatepassDTO.getDocumentDTO()); 

在這一點上,如果你調用.getDocumentDTO().setSomething();從gatepassDTO,或tempDTO,甚至從futureDTO,你總是改變相同的物理對象,這仍然是(引用)的地圖內。

其實,copyProperty不會複製任何東西。

這不會與原始類型,線intchar,也不能與不變對象,像IntegerString和發生;

但是,這將始終與所有其他對象一樣發生,如您編碼的DocumentDTO。

爲了防止這樣的問題,你需要return defensive copies of your objects,這是首選的方式,或者至少手動複製每個屬性,像這樣:

private void copyProperty(GatepassDTO tempDTO,GatepassDTO gatepassDTO){ 
    DocumentDTO src = gatepassDTO.getDocumentDTO(); 
    DocumentDTO dest = new DocumentDTO(); 
    dest.setSomething(src.getSomething()); 
    dest.setSomethingElse(src.getSomethingElse()); 
    dest.setEtc(src.getEtc()); 
    /* go on like that with primitives or immutables, 
    and instantiate new objects for each mutable object you find */ 

    tempDTO.setDocumentDTO(dest); 
    tempDTO.setTruckNo(gatepassDTO.getTruckNo()); 
} 

顯然,如果你把這種邏輯在獲取者,你不需要在你的應用程序中複製這段代碼片段,並且你將防止忘記或寫錯別字的風險。


注1

,以幫助你在這種情況,阿帕奇是存在的。

BeanUtils.copyProperties是你正在尋找的,它會複製每個字段與兩個對象之間的名稱匹配。


注2

您的代碼可以higly重構 ...比如這個:

if(gpDirect!=null){ 
    GatepassDTO tempDTO = new GatepassDTO(); 
    copyProperty(tempDTO,gatepassDTO); 
    putCachedObject("SINGLEGATEPASSCACHE", gatepassNo, tempDTO); 
    gatepassMap.put(gatepassNo, tempDTO); 
    session.put("documentType", documentType); 
    session.put("gatepassMap", gatepassMap); 
    return SUCCESS; 
}else{ 
    GatepassDTO tempDTO = new GatepassDTO(); 
    copyProperty(tempDTO,gatepassDTO); 
    putCachedObject("SINGLEGATEPASSCACHE", gatepassNo, tempDTO); 
    gatepassMap.put(gatepassNo, tempDTO); 
    session.put("documentType", documentType); 
    session.put("gatepassMap", gatepassMap); 
} 

可以寫成

GatepassDTO tempDTO = new GatepassDTO(); 
copyProperty(tempDTO,gatepassDTO); 
putCachedObject("SINGLEGATEPASSCACHE", gatepassNo, tempDTO); 
gatepassMap.put(gatepassNo, tempDTO); 
session.put("documentType", documentType); 
session.put("gatepassMap", gatepassMap); 

if(gpDirect!=null) return SUCCESS; 

把你的時間清理它,它將爲您節省時間和頭痛。