今天在写一个添加平台接口的时候,用到了java反射机制,场景是在Linux服务器上有一个保存方法接口(save),如下所示
@Transactional @Override public Integer save(Long modelId,String sysCode,String userId,Object object) { Field[] fields = object.getClass().getDeclaredFields(); int num = 0 ; for(Field field: fields){ logger.info("当前的反射字段是:"+field); } for (Field field:fields) { ModelProperty modelProperty = new ModelProperty(); modelProperty.setModelProName(field.getName()); ListmodelProperties = modelPropertyDao.getByCondition(modelProperty); InstanceData instanceData = new InstanceData(); if (modelProperties==null || modelProperties.size()==0){ modelProperty.setCreateTime(new Date()); modelProperty.setModelId(modelId); modelProperty.setModifyTime(new Date()); modelProperty.setCreator(userId); modelProperty.setPropertyType(field.getType().toString()); modelPropertyDao.save(modelProperty); instanceData.setModelProId(modelProperty.getModelProId()); }else{ instanceData.setModelProId(modelProperties.get(0).getModelProId()); } instanceData.setSyscode(sysCode); instanceData.setModelId(modelId); instanceData.setCreateTime(new Date()); instanceData.setModifyTime(new Date()); instanceData.setCreator(userId); Object result = getFieldValueByName(field.getName(),object); if (result != null) instanceData.setInstanceValue(result.toString()); num += instanceDataDao.save(instanceData); } return num; } private Object getFieldValueByName(String fieldName, Object o) { try { String firstLetter = fieldName.substring(0, 1).toUpperCase(); String getter = "get" + firstLetter + fieldName.substring(1); Method method = o.getClass().getMethod(getter, new Class[] {}); Object value = method.invoke(o, new Object[] {}); logger.info("获取到的值是:"+value); return value; } catch (Exception e) { e.printStackTrace(); return null; } }
客户端调用服务器的这个接口,我开始传的是addPlatInfo.getClass,结果就是死活没有我定义的属性,都是些不认识的属性,这个问题纠结了很长时间。
@Override public ResultMap addPlatform(String platformName, String platformImg, String platformIntroduce, String[] goodFields,String userId) { AddPlatInfo addPlatInfo = new AddPlatInfo(); addPlatInfo.setPlatName(platformName); addPlatInfo.setImgUrl(platformImg); addPlatInfo.setPlatIntroduction(platformIntroduce); addPlatInfo.setExpertArea(getExpertArea(goodFields)); //test(addPlatInfo,userId); try { int result = instanceDataApi.save(SystemConstant.MODELID,SystemConstant.SYSCODE,userId,addPlatInfo); if(result == 0){ return dealError(new ResultMap(),"添加平台失败!"); } return dealOk(new ResultMap(),"添加平台成功!"); } catch (Exception e) { e.printStackTrace(); return dealError(new ResultMap(),"添加平台失败!"); } }
后来请教别人才知道调用的时候不能用addPlatInfo.getClass()作为参数,下面我把追踪的数据贴出来。
1.刚定义完addPlatInfo时查看对象,如下图所示。
2.addPlatInfo.getClass()所得到的类的属性如下图所示,发现都是些父级类的属性,没有我们定义的那四个属性。
3.addPlatInfo.getClass().getClass()所得到的类的属性如下所示,这时我们看到的属性跟第2步看到的属性一样,只是属性值不一样。
看完了类,下面再看下反射得到的fields。代码如下:
Object obj = addPlatInfo; Field[] fields = obj.getClass().getDeclaredFields();
获取到的fields如下图所示:
再多调一次getClass()
Field[] fieldss = obj.getClass().getClass().getDeclaredFields();
这时再看看fieldss,发现这时获取的字段已经不是我们想要的字段了,因此,客户端在传参数是一定是直接传对象本身,不能传addPlatInfo.getClass()!!!
另外,需要说明的是,反射的对象只有在本工程下可以被识别,如果从客户端传递对象到服务端,服务端要想反射获取值的话,必须也知道这个对象才行!(当然,可以把这个对象放到一个公共的Jar包中,然后客户端和服务端都引用这个jar包也可以)