使用java反射机制遇到的问题
在一个项目中,写外部调用接口的时候,需要使用到Java的反射机制,在使用中发现了反射机制中的一个问题,记录一下,避免再次踩坑。
上代码:
1 /** 2 * 用于外部接口调用 3 * @author 4 * 5 */ 6 public class HttpLinkServlet extends HttpServlet { 7 8 /** 9 * 10 */ 11 private static final long serialVersionUID = -8408900345034346763L; 12 13 private final static String XML_SERVICE_PATH = "Service"; 14 private final static String XML_SERVICE_NAME = "name"; 15 private final static String XML_SERVICE_CLASS = "class"; 16 private final static String XML_SEPARATOR = "_"; 17 private final static String XML_METHOD_PATH = "Method"; 18 private final static String XML_METHOD_CODE = "code"; 19 private Map<String,WSBean> serviceMap = new HashMap<String,WSBean>(); 20 private Map<String,String> methodMap = new HashMap<String,String>(); 21 22 private String wsfile = "/ws/ws.xml"; 23 24 private Logger log = Logger.getLogger(getClass()); 25 26 @Override 27 public void init() throws ServletException { 28 super.init(); 29 //读取配置文件 30 File file = new File(this.getClass().getResource(wsfile).getPath()); 31 XMLHandler xmlHandler = new XMLHandler(file,"UTF-8"); 32 Element rootElement = xmlHandler.getRootElement(); 33 List<?> xList = rootElement.elements(XML_SERVICE_PATH); 34 //放入ws map文件; 35 for (Object serviceObj :xList) {// 获取所有对外公布的service 36 Element serviceElement = (Element) serviceObj; 37 String serviceName = serviceElement.attributeValue(XML_SERVICE_NAME); 38 if (serviceName == null || serviceName.equals("")) { 39 throw new RuntimeException("Invalid bean definition in " + wsfile + "."); 40 } else if (serviceMap.get(serviceName) != null) { 41 throw new RuntimeException("Duplicate webservice beans definition : " + serviceName + "."); 42 } 43 String className = serviceElement.attributeValue(XML_SERVICE_CLASS); 44 if (className == null || className.trim().equals("")) { 45 return; 46 } 47 WSBean beanDef = new WSBean(); 48 beanDef.setName(serviceName); 49 beanDef.setClassName(className); 50 serviceMap.put(serviceName, beanDef); 51 // 将方法对应的方法放入methodMap中 52 for (Object methodObj :serviceElement.elements(XML_METHOD_PATH)) { 53 Element methodElement = (Element) methodObj; 54 String methodCode = methodElement.attributeValue(XML_METHOD_CODE); 55 } 56 } 57 } 58 59 60 @Override 61 protected void doGet(HttpServletRequest req, HttpServletResponse resp) 62 throws ServletException, IOException { 63 doPost(req, resp); 64 } 65 66 @Override 67 protected void doPost(HttpServletRequest req, HttpServletResponse resp) 68 throws ServletException, IOException { 69 System.out.println("======欢迎调用servlet======"+req.getRequestURI() + ":" +req.getContextPath()); 70 String reqPath = req.getRequestURI(); 71 reqPath = reqPath.substring(reqPath.lastIndexOf("/")+1); 72 String userId = req.getHeader("userId"); 73 String password = req.getHeader("password"); 74 String appVersion = req.getHeader("appVersion"); 75 String contentType = req.getHeader("Content-type"); 76 String acceptEncoding = req.getHeader("accept-encoding"); 77 String token = req.getHeader("token"); 78 String sessionId = req.getHeader("easycare.session.id"); 79 String clientIMEI = req.getHeader("client-IMEI"); 80 String clientType = req.getHeader("Client-Type"); 81 82 List<Dict> label = DictUtils.getDictList("apk_version"); 83 84 if (!"loginService".equals(reqPath) && StringUtils.isNotBlank(userId)) { 85 // FIXME:如果包含用户id,且无登录者信息,重新登录 86 Principal p = UserUtils.getPrincipal(); 87 if (p == null) { 88 UserDao userDao = SpringContextHolder.getBean(UserDao.class); 89 User u = userDao.get(userId); 90 String host = StringUtils.getRemoteAddr(req); 91 Subject subject = SecurityUtils.getSubject(); 92 UsernamePasswordToken shiroToken = new UsernamePasswordToken(u.getLoginName(), 93 password.toCharArray(), false, host, null, true); 94 subject.login(shiroToken); 95 } 96 } 97 98 ReturnBO returnBO = new ReturnBO(); 99 try { 100 String reqJson = acceptJSON(req);//得到requestContext 101 RequestBO requestBO = (RequestBO)JsonMapper.fromJsonString(reqJson, RequestBO.class); 102 // JSONObject jsonObj = JSONObject.parseObject(reqJson);//转换成JSONObject 103 if (requestBO == null) { 104 returnBO.setResultStr("请求参数为空,请联系管理员! "); 105 } else { 106 String action = requestBO.getAction();// 请求方法 107 if(StringUtils.isNotBlank(action)){ 108 if(methodMap.keySet()!=null&&methodMap.keySet().size()>0){ 109 if(methodMap.keySet().contains(reqPath + XML_SEPARATOR + action)){ 110 String beanName = methodMap.get(reqPath + XML_SEPARATOR + action); 111 if (beanName != null && !beanName.trim().equals("")) { 112 WSBean wsBean =((WSBean)serviceMap.get(beanName)); 113 Object bean=SpringContextHolder.getBean(wsBean.getName()); 114 115 if (bean != null) { 116 @SuppressWarnings("rawtypes") 117 Class clazz = bean.getClass(); 118 // 遍历所有方法 119 // 获取方法 120 Method[] allMethods = clazz.getMethods(); 121 Method method = null; 122 for (Method _method : allMethods) { 123 if (_method.getName().equals(action)) { 124 method = _method; 125 break; 126 } 127 } 128 if (null == method) { 129 throw new RuntimeException("【"+ clazz.getName() + "】中不存在方法:【" + action +"】"); 130 } 131 // 参数转换,将json转化为对象 132 Object[] parameter = null; 133 Class<?>[] parameterTypes = method.getParameterTypes(); 134 Class<?> methodParameterType = null; 135 if (null != parameterTypes && parameterTypes.length > 0) { 136 parameter = new Object[parameterTypes.length]; 137 //解决乱码问题 138 String data = new String(requestBO.getParam().getBytes("UTF-8"),"UTF-8"); 139 JSONArray dataArray = JSONArray.parseArray(data); 140 for (int i = 0; i < parameterTypes.length; i++) { 141 methodParameterType = parameterTypes[i]; 142 JSONObject tmpObj = dataArray.getJSONObject(i); 143 parameter[i] = JSONUtils.toBean(tmpObj.toJSONString(), methodParameterType); 144 } 145 } 146 // 方法调用 147 Object returnObj = null; 148 if (null != methodParameterType) {// 参数不为空时 149 returnObj = ReflectionUtils.invokeMethod(method, bean, parameter); 150 } else { 151 returnObj = method.invoke(bean); 152 } 153 returnBO.setFlag(Global.TRUE); 154 returnBO.setResultStr(JsonMapper.toJsonString(returnObj)); 155 } 156 } 157 } else { 158 returnBO.setResultStr("action【 "+action+"】服务已停止,请联系管理员! "); 159 } 160 } 161 } else { 162 returnBO.setResultStr("action 参数为空,请联系管理员!"); 163 } 164 } 165 166 } catch (Exception e) { 167 returnBO.setResultStr(e.getMessage()); 168 log.error(e.getMessage()); 169 } 170 log.info("return json: "+JsonMapper.toJsonString(returnBO)); 171 // 输出返回JSON字符串 172 resp.reset(); 173 resp.setContentType("application/json"); 174 resp.setCharacterEncoding("UTF-8"); 175 resp.getWriter().println(JsonMapper.toJsonString(returnBO)); 176 resp.addIntHeader("result-code", returnBO.getResultCode()); 177 resp.setHeader("apkVesion", label.get(0).getValue()); 178 } 179 180 /** 181 * 接收客户端Json参数 182 * @param request 183 * @return 184 */ 185 public String acceptJSON(HttpServletRequest request) { 186 String acceptjson = ""; 187 try { 188 BufferedReader br = new BufferedReader( 189 new InputStreamReader((ServletInputStream) request.getInputStream(), "utf-8")); 190 StringBuffer sb = new StringBuffer(""); 191 String temp; 192 while ((temp = br.readLine()) != null) { 193 sb.append(temp); 194 } 195 br.close(); 196 acceptjson = sb.toString(); 197 System.out.println(acceptjson); 198 } catch (Exception e) { 199 e.printStackTrace(); 200 } 201 return acceptjson; 202 } 203 204 }
在标红处,一直得不到正确的参数类型,要么是一个Object,要嘛是其他类型的参数。
原因是:因为我要获得的参数是个对象,而这个对象A又继承了另一个对象B,另一个对象B又继承于另一个对象C,这样的话,你得到的参数类型应该会出现4种(Object、A、B、C)
解决方法是:在写一个方法去调用原方法(相当于写一个接口),明确参数的类型
例:
1 public List<Leasecredit> findList(Leasecredit leasecredit) { 2 //加入过滤数据范围 3 leasecredit.getSqlMap().put("dsf", dataScopeFilter(UserUtils.getUser(), "o", "u")); 4 return super.findList(leasecredit); 5 } 6 7 public List<Leasecredit> findListInterface(Leasecredit leasecredit) { 8 return findList(leasecredit); 9 }