/* * JEF - Copyright 2009-2010 Jiyi (mr.jiyi@gmail.com) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package jef.tools; import java.io.File; import java.io.IOException; import java.lang.reflect.Array; import java.text.ParseException; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Queue; import java.util.Set; import jef.common.IntList; import jef.common.log.LogUtil; import jef.tools.reflect.BeanUtils; import jef.tools.reflect.BeanWrapperImpl; import jef.tools.reflect.ClassEx; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; import org.xml.sax.SAXException; /** * JXB与JAXB类似,是JEF中为了实现Java对象和XML绑定所编写的工具 * * @author Jiyi */ public class JXB { private JXB() { }; /** * 将一个XML节点转化为对象 * * @param e * @return * @throws InstantiationException * @throws IllegalAccessException */ public static Object elementToObject(Element e) throws InstantiationException, IllegalAccessException { return classElementToObject(e, new HashMap<String, Object>()); } /** * 将XML节点内容填充到指定的对象中 * * @param e * @param obj * @throws IllegalAccessException * @throws InstantiationException */ public static void populateObject(Element e, Object obj) throws InstantiationException, IllegalAccessException { populateObject(e, obj, new HashMap<String, Object>()); } /** * 将对象转化为XML * * @param parent * 对象节点将挂在此节点下 * @param obj */ public static Element objectToXML(Object obj, Node parent) { HashMap<Integer, Element> objs = new HashMap<Integer, Element>(); IntList referd = new IntList(); Element e = objectToXML(parent, obj, objs, referd,null); for (Integer i : objs.keySet()) { if (!referd.contains(i)) {// 仅有被引用的对象才需要hashcode,删除不需要hashCode的节点,让XML更清晰一些 Element e1 = objs.get(i); e1.removeAttribute("hashCode"); } } return e; } private static void populateObject(Element e, Object obj, HashMap<String, Object> objects) throws InstantiationException, IllegalAccessException { BeanWrapperImpl bean = new BeanWrapperImpl(obj); NamedNodeMap attribs = e.getAttributes(); for (int i = 0; i < attribs.getLength(); i++) { Node nd = attribs.item(i); String name = dashToUpper(nd.getNodeName(), false); String fieldName = bean.findPropertyIgnoreCase(name); if (fieldName != null && bean.isWritableProperty(fieldName)) { setValue(bean, fieldName, nd, objects); } } for (Element sub : XMLUtils.childElements(e)) { String name = dashToUpper(sub.getNodeName(), false); String fieldName = bean.findPropertyIgnoreCase(name); if (fieldName != null && bean.isWritableProperty(fieldName)) { setValue(bean, fieldName, sub, objects); } } } /* * @param parent 上节点 * * @param obj 数据 * * @param objects 已经处理对象 * * @param refedHash * * @return */ private static Element objectToXML(Node parent, Object obj, Map<Integer, Element> objects, IntList refedHash,Class<?> fieldContainer) { if (obj == null) { Element root = (parent.getNodeType() == Node.DOCUMENT_NODE) ? ((Document) parent).createElement("null") : parent.getOwnerDocument().createElement("null"); return root; } Class<?> c = obj.getClass(); String classname = (c.isArray()) ? "Array_" + c.getComponentType().getName() : c.getName(); classname = classname.replace('$', '_'); Element objElement; if(fieldContainer==null){ objElement = (parent.getNodeType() == Node.DOCUMENT_NODE) ? ((Document) parent).createElement(classname) : parent.getOwnerDocument().createElement(classname); parent.appendChild(objElement); }else{ objElement=(Element)parent; } // 开始处理 if (objects.containsKey(obj.hashCode())) { objElement.setAttribute("ref-hashCode", String.valueOf(obj.hashCode())); refedHash.add(obj.hashCode()); return objElement; } else { objElement.setAttribute("hashCode", String.valueOf(obj.hashCode())); objects.put(obj.hashCode(), objElement);// 标记已经处理 } if (processIterator(c, obj, objElement, objects, refedHash)) {// 如果是可枚举的对象 return objElement; } else if (classname.startsWith("java.lang")) {// java基本对象 objElement.setAttribute("value", String.valueOf(obj)); return objElement; } else { BeanWrapperImpl bean = new BeanWrapperImpl(obj); for (String fieldName : bean.getRwPropertyNames()) { appendValue(bean, fieldName, objElement, objects, refedHash); } } return objElement; } public static String dashToUpper(String name, boolean capitalize) { if (name.indexOf('-') < 0) return name; char[] r = new char[name.length()]; int n = 0; boolean nextUpper = capitalize; for (char c : name.toCharArray()) { if (c == '-') { nextUpper = true; } else { if (nextUpper) { r[n] = Character.toUpperCase(c); nextUpper = false; } else { r[n] = Character.toLowerCase(c); } n++; } } return new String(r, 0, n); } /** * 将以类名为节点名的节点转换为对象 */ private static Object classElementToObject(Element e, HashMap<String, Object> objects) throws InstantiationException, IllegalAccessException { String nodeName = dashToUpper(e.getNodeName(), false); String hashId = XMLUtils.attrib(e, "hashCode"); String ref_hashId = XMLUtils.attrib(e, "ref-hashCode"); Object obj; if (nodeName.startsWith("Array_")) { try { obj = processIteratorElement(nodeName, e, objects); } catch (ClassNotFoundException e1) { throw new IllegalAccessException("ClassNotFound:" + e1.getMessage()); } return obj; } if (nodeName.indexOf(".") > -1) {// 肯定是类名 String s = XMLUtils.attrib(e, "value"); if (s == null) s = XMLUtils.nodeText(e); if ("java.lang.String".equals(nodeName)) { obj = s; } else if ("java.lang.Long".equals(nodeName)) { if ("null".equals(s) || s == null) return null; obj = Long.valueOf(s); } else if ("java.lang.Integer".equals(nodeName)) { if ("null".equals(s) || s == null) return null; obj = Integer.valueOf(s); } else if ("java.lang.Short".equals(nodeName)) { if ("null".equals(s) || s == null) return null; obj = Short.valueOf(s); } else if ("java.lang.Float".equals(nodeName)) { if ("null".equals(s) || s == null) return null; obj = Float.valueOf(s); } else if ("java.lang.Double".equals(nodeName)) { if ("null".equals(s) || s == null) return null; obj = Double.valueOf(s); } else if ("java.lang.Byte".equals(nodeName)) { if ("null".equals(s) || s == null) return null; obj = Byte.valueOf(s); } else if ("java.lang.Boolean".equals(nodeName)) { if ("null".equals(s) || s == null) return null; obj = Boolean.valueOf(s); } else if ("java.lang.Character".equals(nodeName)) { if ("null".equals(s) || s == null) return null; obj = XMLUtils.nodeText(e).charAt(0); } else { if (ref_hashId != null) { obj = objects.get(ref_hashId); Assert.notNull(obj); } else { try { nodeName = nodeName.replace('_', '$'); obj = processIteratorElement(nodeName, e, objects); if (obj == null) { Class<?> c = Class.forName(nodeName); obj = c.newInstance(); if (hashId != null) { objects.put(hashId, obj); } populateObject(e, obj, objects); } } catch (ClassNotFoundException e1) { throw new IllegalAccessException("ClassNotFound:" + e1.getMessage()); } } return obj; } } else {// 可能是无包名的类,也可能是某个未开放的字段名,无法处理 throw new IllegalArgumentException("Unknown element class:" + nodeName); } if (hashId != null) { objects.put(hashId, obj); } return obj; } // 将数组或集合类型的对象转化为XML private static boolean processIterator(Class<?> c, Object obj, Element root, Map<Integer, Element> objects, IntList list) { if (c.isArray()) { if (c.getComponentType().isPrimitive()) {// 是原生类型数组 Object[] objArray = ArrayUtils.toObject(obj);// 强制将原生类型转换为对象类型(装箱) for (Object ele : objArray) { objectToXML(root, ele, objects, list,null); } } else {// 对象数组 for (Object ele : (Object[]) obj) { objectToXML(root, ele, objects, list,null); } } return true; } else if (List.class.isAssignableFrom(c)) { for (Object ele : (List<?>) obj) { objectToXML(root, ele, objects, list,null); } return true; } else if (Set.class.isAssignableFrom(c)) { for (Object ele : (Set<?>) obj) { objectToXML(root, ele, objects, list,null); } return true; } else if (Map.class.isAssignableFrom(c)) { Map<?, ?> map = (Map<?, ?>) obj; for (Object ele : map.keySet()) { Element entry = root.getOwnerDocument().createElement("Entry"); root.appendChild(entry); Element key = objectToXML(entry, ele, objects, list,null); key.setAttribute("entry_type", "key"); Element value = objectToXML(entry, map.get(ele), objects, list,null); value.setAttribute("entry_type", "value"); } return true; } else if (Queue.class.isAssignableFrom(c)) { for (Object ele : (Set<?>) obj) { objectToXML(root, ele, objects, list, null); } return true; } return false; } // 将对象的字段中的值写入XML节点上 private static void appendValue(BeanWrapperImpl bean, String fieldName, Element current, Map<Integer, Element> objects, IntList list) { Object value = bean.getPropertyValue(fieldName); if (value == null) return; // ?bean.getFieldType(fieldName): Class<?> type = BeanUtils.toWrapperClass(bean.getPropertyRawType(fieldName)); Class<?> c = value.getClass(); Element element = null; if (String.class == c) { element = XMLUtils.addElement(current, fieldName, (String) value); } else if (Date.class == c) { element = XMLUtils.addElement(current, fieldName, DateUtils.formatDateTime((Date) value)); } else if (Integer.class == c || Integer.TYPE == c) { element = XMLUtils.addElement(current, fieldName, String.valueOf(value)); } else if (Boolean.class == c || Boolean.TYPE == c) { element = XMLUtils.addElement(current, fieldName, String.valueOf(value)); } else if (Double.class == c || Double.TYPE == c) { element = XMLUtils.addElement(current, fieldName, String.valueOf(value)); } else if (Float.class == c || Float.TYPE == c) { element = XMLUtils.addElement(current, fieldName, String.valueOf(value)); } else if (Byte.class == c || Byte.TYPE == c) { element = XMLUtils.addElement(current, fieldName, String.valueOf(value)); } else if (Character.class == c || Character.TYPE == c) { element = XMLUtils.addElement(current, fieldName, String.valueOf(value)); } else if (Long.class == c || Long.TYPE == c) { element = XMLUtils.addElement(current, fieldName, String.valueOf(value)); } else if (Short.class == c || Short.TYPE == c) { element = XMLUtils.addElement(current, fieldName, String.valueOf(value)); } else if (c.isEnum()) { element = XMLUtils.addElement(current, fieldName, String.valueOf(value)); } else if (c.getName().startsWith("java.lang")) {// java基本对象 element = XMLUtils.addElement(current, fieldName, String.valueOf(value)); } else { Element field = XMLUtils.addElement(current, fieldName); objectToXML(field, value, objects, list, type); } if (type != c && element!=null) { element.setAttribute("class", c.getSimpleName()); } } // 将XML节点上的值写入到对象中 @SuppressWarnings({ "unchecked" }) private static void setValue(BeanWrapperImpl bean, String fieldName, Node sub, HashMap<String, Object> objects) throws InstantiationException, IllegalAccessException { ClassEx c = new ClassEx(bean.getProperty(fieldName).getType()); String value = null; if (sub.getNodeType() == Node.ATTRIBUTE_NODE) { value = sub.getNodeValue(); } else if (sub.getNodeType() == Node.ELEMENT_NODE) { value = XMLUtils.nodeText((Element) sub); } else { return; } // 根据目标对象中的字段属性来赋值 if (String.class == c.getWrappered()) { bean.setPropertyValue(fieldName, value); } else if (Date.class == c.getWrappered()) { try { Date d = DateUtils.parseDateTime(value); bean.setPropertyValue(fieldName, d); } catch (ParseException ex) { LogUtil.exception(ex); } } else if (c.getWrappered() == Integer.class || "int".equals(c.getName())) { bean.setPropertyValue(fieldName, StringUtils.toInt(value, 0)); } else if (Boolean.class == c.getWrappered() || "boolean".equals(c.getName())) { bean.setPropertyValue(fieldName, StringUtils.toBoolean(value, false)); } else if (Double.class == c.getWrappered() || "double".equals(c.getName())) { bean.setPropertyValue(fieldName, StringUtils.toDouble(value, 0.0)); } else if (Float.class == c.getWrappered() || "float".equals(c.getName())) { bean.setPropertyValue(fieldName, StringUtils.toFloat(value, 0f)); } else if (Byte.class == c.getWrappered() || "byte".equals(c.getName())) { bean.setPropertyValue(fieldName, (byte) StringUtils.toInt(value, 0)); } else if (Character.class == c.getWrappered() || "char".equals(c.getName())) { if (value.length() > 0) { bean.setPropertyValue(fieldName, value.substring(0, 1)); } } else if (Long.class == c.getWrappered() || "long".equals(c.getName())) { bean.setPropertyValue(fieldName, StringUtils.toLong(value, 0L)); } else if (Short.class == c.getWrappered() || "short".equals(c.getName())) { bean.setPropertyValue(fieldName, StringUtils.toInt(value, 0)); } else if (c.isEnum()) { bean.setPropertyValue(fieldName, Enum.valueOf(c.getWrappered().asSubclass(Enum.class), value)); } else { Element detailNode = (Element) XMLUtils.first(sub, Node.ELEMENT_NODE); if (detailNode != null) { Object obj = classElementToObject(detailNode, objects); if (obj != null) { bean.setPropertyValue(fieldName, obj); } } else if (sub.getNodeType() == Node.ATTRIBUTE_NODE || value != null) { bean.setPropertyValue(fieldName, value); } } } // 将XML中列表元素转换为Array,List,Map,Set,Queue等对象,如果不是上述对象则返回Null @SuppressWarnings({ "unchecked", "rawtypes" }) private static Object processIteratorElement(String className, Element arrayNode, HashMap<String, Object> objects) throws IllegalAccessException, InstantiationException, ClassNotFoundException { String nodeName = arrayNode.getNodeName(); String hashId = XMLUtils.attrib(arrayNode, "hashCode"); String ref_hashId = XMLUtils.attrib(arrayNode, "ref-hashCode"); Object result = null; if (ref_hashId != null) { Assert.isTrue(objects.containsKey(ref_hashId)); return objects.get(ref_hashId); } if (className.startsWith("Array_")) {// 必须先知道数组有多少个元素 String compName = StringUtils.substringAfter(className, "_"); String objName = primitiveNameToObjName(compName); boolean isPrimitive = (compName != objName); List<Element> elements = XMLUtils.childElements(arrayNode); try { Object[] objs = (Object[]) Array.newInstance(Class.forName(primitiveNameToObjName(compName)), elements.size()); for (int i = 0; i < elements.size(); i++) { Element eleNode = elements.get(i); objs[i] = classElementToObject(eleNode, objects); if (isPrimitive && objs[i] == null) {// 原生类型不可以为NULL throw new RuntimeException("primitive type must not be NULL"); } } if (isPrimitive) {// 是基本类型的数组 result = ArrayUtils.toPrimitive(objs); } else { result = objs; } } catch (NegativeArraySizeException e) { throw new IllegalAccessException(e.getMessage()); } catch (ClassNotFoundException e) { throw new IllegalAccessException(e.getMessage()); } } if (result == null) { Class c = Class.forName(className); if (Map.class.isAssignableFrom(c)) { Class impl = Class.forName(nodeName); Map<Object, Object> objs = (Map<Object, Object>) impl.newInstance(); List<Element> elements = XMLUtils.childElements(arrayNode); for (Element entry : elements) { Element keyE = null; Element valueE = null; for (Element e : XMLUtils.childElements(entry)) { String eeType = e.getAttribute("entry_type"); if ("key".equals(eeType)) { keyE = e; } else if ("value".equals(eeType)) { valueE = e; } } Assert.notNull(keyE); Assert.notNull(valueE); Object key = classElementToObject(keyE, objects); Object value = classElementToObject(valueE, objects); objs.put(key, value); } result = objs; } else if (List.class.isAssignableFrom(c)) { Class impl = Class.forName(nodeName); List<Object> objs = (List<Object>) impl.newInstance(); List<Element> elements = XMLUtils.childElements(arrayNode); for (Element eleNode : elements) { objs.add(classElementToObject(eleNode, objects)); } result = objs; } else if (Set.class.isAssignableFrom(c)) { Class impl = Class.forName(nodeName); Set<Object> objs = (Set<Object>) impl.newInstance(); List<Element> elements = XMLUtils.childElements(arrayNode); for (Element eleNode : elements) { objs.add(classElementToObject(eleNode, objects)); } result = objs; } else if (Queue.class.isAssignableFrom(c)) { Class impl = Class.forName(nodeName); Queue<Object> objs = (Queue<Object>) impl.newInstance(); List<Element> elements = XMLUtils.childElements(arrayNode); for (Element eleNode : elements) { objs.add(classElementToObject(eleNode, objects)); } result = objs; } } if (hashId != null && result != null) { objects.put(hashId, result); } return result; } // 从原生名称得到对象名称 private static String primitiveNameToObjName(String compName) { if ("int".equals(compName)) { return Integer.class.getName(); } else if ("boolean".equals(compName)) { return Boolean.class.getName(); } else if ("long".equals(compName)) { return Long.class.getName(); } else if ("short".equals(compName)) { return Short.class.getName(); } else if ("float".equals(compName)) { return Float.class.getName(); } else if ("byte".equals(compName)) { return Byte.class.getName(); } else if ("char".equals(compName)) { return Character.class.getName(); } else if ("double".equals(compName)) { return Double.class.getName(); } else { return compName; } } /** * 将对象用JXB序列化为XML保存 * * @param obj * @param file * @return */ public static boolean saveObjectToXML(Object obj, File file) { try { Document doc = XMLUtils.newDocument(); JXB.objectToXML(obj, doc); XMLUtils.saveDocument(doc, file, "UTF-8"); return true; } catch (Exception e) { LogUtil.exception(e); return false; } } /** * 将JXB保存的对象还原 * * @param file * @return * @throws SAXException * @throws IOException * @throws InstantiationException * @throws IllegalAccessException */ public static Object loadObjectFromXML(File file) throws SAXException, IOException, InstantiationException, IllegalAccessException { Document doc = XMLUtils.loadDocument(file); Object obj = JXB.elementToObject(doc.getDocumentElement()); return obj; } }