3

In My recent project, I am using jQuery Grid, generating dynamic grids when user click on button.

At server side data is manipulated by using the Session.

First I am getting Session object and casting that object to gatepassDTO.

Then I am creating one local object and I am copying properties from old to new object and putting into the Map.

After that I am creating futureDTO object and copying properties from gatepassDTO to futureDTO. If I change anything in futureDTO it effects on the Map that contains object.

Why this happens?

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

Why this problem occurs? Is this core Java problem or Struts2 JSON problem?

4

2 に答える 2

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() の参照を AGAIN に割り当てます。

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

この時点で、.getDocumentDTO().setSomething();gatepassDTO、または tempDTO、さらには futureDTO から呼び出した場合、マップ内でまだ (参照されている) 同じ物理オブジェクトを常に変更しています。

実際、copyProperty は何もコピーしていません。

これは、プリミティブ型、 lineintおよびchar、およびのような不変オブジェクトでは発生しません。IntegerString

ただし、これは、コーディングした DocumentDTO など、他のすべてのオブジェクトで常に発生します。

この種の問題を防ぐには、オブジェクトの防御的なコピーを返す必要があります。これが推奨される方法です。または、少なくとも次のように各プロパティを手動でコピーする必要があります。

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

この種のロジックを getter に配置すると、アプリケーションでこのコード スニペットを複製する必要がなくなり、何かを忘れたりタイプミスを書いたりするリスクを防ぐことができます。


注1

この種の状況で役立つように、Apache が用意されています。

BeanUtils.copyProperties探しているものは、2 つのオブジェクト間で名前が一致するすべてのフィールドをコピーします。


注2

コードは高度にリファクタリングされる可能性があります...たとえば、次のようになります。

 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;

時間をかけてクリーンアップしてください。将来的に時間と頭痛の種を節約できます。

于 2013-07-16T10:14:49.987 に答える