2013-07-16 2 views
3

최근 프로젝트에서 사용자가 버튼을 클릭 할 때 동적 격자를 생성하는 jQuery Grid를 사용하고 있습니다.여러 DTO가 세션 맵을 변경하는 이유는 무엇입니까?

서버 측에서는 Session을 사용하여 데이터를 조작합니다.

먼저 Session 개체를 가져 와서 해당 개체를 gatepassDTO으로 전송 중입니다.

그런 다음 하나의 로컬 객체를 만들고 있는데 이전 객체에서 새 객체로 속성을 복사하고 Map에 배치하고 있습니다.

그런 다음 futureDTO 개체를 만들고 gatepassDTO에서 futureDTO으로 속성을 복사 중입니다. 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()); 
    } 

왜이 문제가 발생합니까? 이 핵심 자바 문제 또는 Struts2 JSON 문제가 있습니까?

+0

무엇이 문제입니까? 예를 들어, 향후 DTO의 "DocumentDTO"를 변경하면 세션의 객체에도 영향을 미칩니 까? – mael

+0

예? iam이 미래의 dtoDocument 데이터를 변경하는 경우 Hasmap에 tempDTO가 포함되어 있습니다. 코어 자바에서 똑같은 작업을 시도했지만 프로젝트에서 제대로 작동합니다. – user1965582

답변

0

지도에서 개체를 가져올 때 개체 복사본을 가져 오지 않으면 해당 개체에 대한 참조가 나타납니다. 즉, 객체의 속성을 변경하면 해시 맵의 "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의 인스턴스를 다시 gatepassDTO.getDocumentDTO()의 참조를 지정하려면 (즉 참조 자체)

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

이 시점에서 gatepassDTO 또는 tempDTO 또는 futureDTO에서 .getDocumentDTO().setSomething();을 호출하면지도 내에서 여전히 (참조 된) 동일한 실제 객체를 항상 변경하고 있습니다.

실제로 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()); 
} 

을 getters를 사용하면 응용 프로그램에서이 코드 스 니펫을 복제 할 필요가 없으며 무언가를 잊어 버리거나 오타가 생길 위험을 방지 할 수 있습니다.


상황의이 종류에 도움, 아파치가

이다 주 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; 

시간을 가지고 같이 쓸 수있다 그것을 청소, 그것 앞으로 시간과 두통을 덜어 줄 것입니다.