在我最近的项目中,我正在使用jQuery Grid,当用户点击按钮时生成动态网格。
在服务器端,使用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());
}
为什么会出现此问题? 这是核心Java问题还是Struts2 JSON问题?
答案 0 :(得分:1)
您正在使用引用(将它们视为指针)。
从Session Map获取对象时,您将获得它的引用(即使Map只包含引用,而不是真实对象)
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());
此时,如果你从gatepassDTO或tempDTO,甚至来自futureDTO调用.getDocumentDTO().setSomething();
,你总是要改变相同的物理对象,即在地图中仍然(引用)。
实际上,copyProperty并没有复制任何东西。
原始类型 ,行int
和char
以及 不可变对象< / em> ,例如Integer
和String
;
但是这将永远发生在所有其他对象上,例如您编码的对象,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());
}
显然,如果你把这种逻辑放在getter中,你就不需要在你的应用程序中复制这段代码片段了,你就可以防止遗忘或写错字的风险。
注1
在这种情况下帮助你,Apache就在那里。
BeanUtils.copyProperties
正是您要找的,它会复制两个对象之间名称匹配的每个字段。
Note2
您的代码可以重构 ...例如:
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;
花点时间清理它,这将为您节省时间和头痛。
答案 1 :(得分:0)
当您从Map获取对象时,您没有获得该对象的副本,您将获得对该对象的引用。这意味着如果更改对象的属性,则hashmap中的对象“in”也会更改其属性(因为它是同一个对象)。
这是您的代码所发生的事情: