📄 mxobjectcodec.java
字号:
/** * Returns the XML node attribute name for the given Java field name. That * is, it returns the mapping of the field name. */ protected String getAttributeName(String fieldname) { if (fieldname != null) { Object mapped = mapping.get(fieldname); if (mapped != null) { fieldname = mapped.toString(); } } return fieldname; } /** * Returns the Java field name for the given XML attribute name. That is, it * returns the reverse mapping of the attribute name. * * @param attributename * The attribute name to be mapped. * @return String that represents the mapped field name. */ protected String getFieldName(String attributename) { if (attributename != null) { Object mapped = reverse.get(attributename); if (mapped != null) { attributename = mapped.toString(); } } return attributename; } /** * Returns the field with the specified name. */ protected Field getField(Object obj, String fieldname) { Class type = obj.getClass(); while (type != null) { try { Field field = type.getDeclaredField(fieldname); if (field != null) { return field; } } catch (Exception e) { // ignore } type = type.getSuperclass(); } return null; } /** * Returns the accessor (getter, setter) for the specified field. */ protected Method getAccessor(Object obj, Field field, boolean isGetter) { String name = field.getName(); name = name.substring(0, 1).toUpperCase() + name.substring(1); if (!isGetter) { name = "set" + name; } else if (boolean.class.isAssignableFrom(field.getType())) { name = "is" + name; } else { name = "get" + name; } try { if (isGetter) { return getMethod(obj, name, null); } else { return getMethod(obj, name, new Class[] { field.getType() }); } } catch (Exception e1) { // ignore } return null; } /** * Returns the method with the specified signature. */ protected Method getMethod(Object obj, String methodname, Class[] params) { Class type = obj.getClass(); while (type != null) { try { Method method = type.getDeclaredMethod(methodname, params); if (method != null) { return method; } } catch (Exception e) { // ignore } type = type.getSuperclass(); } return null; } /** * Returns the value of the field with the specified name in the specified * object instance. */ protected Object getFieldValue(Object obj, String fieldname) { Object value = null; if (obj != null && fieldname != null) { Field field = getField(obj, fieldname); try { if (field != null) { value = field.get(obj); } } catch (IllegalAccessException e1) { if (field != null) { try { Method method = getAccessor(obj, field, true); value = method.invoke(obj, (Object[]) null); } catch (Exception e2) { // ignore } } } catch (Exception e) { // ignore } } return value; } /** * Sets the value of the field with the specified name * in the specified object instance. */ protected void setFieldValue(Object obj, String fieldname, Object value) { Field field = null; try { field = getField(obj, fieldname); if (field.getType() == Boolean.class) { value = new Boolean(value.equals("1") || String.valueOf(value).equalsIgnoreCase("true")); } field.set(obj, value); } catch (IllegalAccessException e1) { if (field != null) { try { Method method = getAccessor(obj, field, false); Class type = method.getParameterTypes()[0]; value = convertValueFromXml(type, value); method.invoke(obj, new Object[] { value }); } catch (Exception e2) { System.err.println("setFieldValue: " + e2 + " on " + obj.getClass().getSimpleName() + "." + fieldname + " (" + field.getType().getSimpleName() + ") = " + value + " (" + value.getClass().getSimpleName() + ")"); } } } catch (Exception e) { // ignore } } /** * Hook for subclassers to pre-process the object before encoding. This * returns the input object. The return value of this function is used in * encode to perform the default encoding into the given node. * * @param enc Codec that controls the encoding process. * @param obj Object to be encoded. * @param node XML node to encode the object into. * @return Returns the object to be encoded by the default encoding. */ public Object beforeEncode(mxCodec enc, Object obj, Node node) { return obj; } /** * Hook for subclassers to post-process the node for the given object after * encoding and return the post-processed node. This implementation returns * the input node. The return value of this method is returned to the * encoder from <encode>. * * Parameters: * * @param enc Codec that controls the encoding process. * @param obj Object to be encoded. * @param node XML node that represents the default encoding. * @return Returns the resulting node of the encoding. */ public Node afterEncode(mxCodec enc, Object obj, Node node) { return node; } /** * Parses the given node into the object or returns a new object * representing the given node. * * @param dec Codec that controls the encoding process. * @param node XML node to be decoded. * @return Returns the resulting object that represents the given XML node. */ public Object decode(mxCodec dec, Node node) { return decode(dec, node, null); } /** * Parses the given node into the object or returns a new object * representing the given node. * * Dec is a reference to the calling decoder. It is used to decode complex * objects and resolve references. * * If a node has an id attribute then the object cache is checked for the * object. If the object is not yet in the cache then it is constructed * using the constructor of <template> and cached in <mxCodec.objects>. * * This implementation decodes all attributes and childs of a node according * to the following rules: * - If the variable name is in <exclude> or if the attribute name is "id" * or "as" then it is ignored. - If the variable name is in <idrefs> then * <mxCodec.getObject> is used to replace the reference with an object. - * The variable name is mapped using a reverse <mapping>. - If the value has * a child node, then the codec is used to create a child object with the * variable name taken from the "as" attribute. - If the object is an array * and the variable name is empty then the value or child object is appended * to the array. - If an add child has no value or the object is not an * array then the child text content is evaluated using <mxUtils.eval>. * * If no object exists for an ID in <idrefs> a warning is issued using * <mxLog.warn>. * * @param dec Codec that controls the encoding process. * @param node XML node to be decoded. * @param into Optional objec to encode the node into. * @return Returns the resulting object that represents the given XML node * or the object given to the method as the into parameter. */ public Object decode(mxCodec dec, Node node, Object into) { Object obj = null; if (node instanceof Element) { String id = ((Element) node).getAttribute("id"); obj = dec.objects.get(id); if (obj == null) { obj = into; if (obj == null) { obj = cloneTemplate(node); } if (id != null && id.length() > 0) { dec.putObject(id, obj); } } node = beforeDecode(dec, node, obj); decodeNode(dec, node, obj); obj = afterDecode(dec, node, obj); } return obj; } /** * Calls decodeAttributes and decodeChildren for the given node. */ protected void decodeNode(mxCodec dec, Node node, Object obj) { if (node != null) { decodeAttributes(dec, node, obj); decodeChildren(dec, node, obj); } } /** * Decodes all attributes of the given node using decodeAttribute. */ protected void decodeAttributes(mxCodec dec, Node node, Object obj) { NamedNodeMap attrs = node.getAttributes(); if (attrs != null) { for (int i = 0; i < attrs.getLength(); i++) { Node attr = attrs.item(i); decodeAttribute(dec, attr, obj); } } } /** * Reads the given attribute into the specified object. */ protected void decodeAttribute(mxCodec dec, Node attr, Object obj) { String name = attr.getNodeName(); if (!name.equalsIgnoreCase("as") && !name.equalsIgnoreCase("id")) { Object value = attr.getNodeValue(); String fieldname = getFieldName(name); if (isReference(obj, fieldname, value, false)) { Object tmp = dec.getObject(String.valueOf(value)); if (tmp == null) { System.err.println("mxObjectCodec.decode: No object for " + mxCodecRegistry.getName(obj.getClass()) + "." + fieldname + "=" + value); return; // exit } value = tmp; } if (!isExcluded(obj, fieldname, value, false)) { setFieldValue(obj, fieldname, value); // mxLog.debug(type+"."+name+"="+value); } } } /** * Decodec all children of the given node using decodeChild. */ protected void decodeChildren(mxCodec dec, Node node, Object obj) { Node child = node.getFirstChild(); while (child != null) { if (child.getNodeType() == Node.ELEMENT_NODE && !this.processInclude(dec, child, obj)) { decodeChild(dec, child, obj); } child = child.getNextSibling(); } } /** * Reads the specified child into the given object. */ protected void decodeChild(mxCodec dec, Node child, Object obj) { String fieldname = getFieldName(((Element) child).getAttribute("as")); if (fieldname == null || !isExcluded(obj, fieldname, child, false)) { Object value = null; Object template = getFieldValue(obj, fieldname); if (child.getNodeName().equals("add")) { value = ((Element) child).getAttribute("value"); if (value == null) { value = child.getTextContent(); // mxLog.debug("Decoded "+role+" // "+mxUtils.getTextContent(child)); } } else { value = dec.decode(child, template); // System.out.println("Decoded " + child.getNodeName() + "." // + fieldname + "=" + value); } if (value != null && !value.equals(template)) { if (fieldname != null && obj instanceof Map) { ((Map) obj).put(fieldname, value); } else if (fieldname != null && fieldname.length() > 0) { setFieldValue(obj, fieldname, value); } else if (obj instanceof Collection) { ((Collection) obj).add(value); } else if (obj.getClass().isArray()) { // FIXME: add to array } // mxLog.debug("Decoded "+type+"."+role+": "+tmp); } } } /** * Returns true if the given node is an include directive and executes the * include by decoding the XML document. Returns false if the given node is * not an include directive. * * @param dec Codec that controls the encoding/decoding process. * @param node XML node to be checked. * @param into Optional object to pass-thru to the codec. * @return Returns true if the given node was processed as an include. */ public boolean processInclude(mxCodec dec, Node node, Object into) { if (node.getNodeType() == Node.ELEMENT_NODE && node.getNodeName().equalsIgnoreCase("include")) { String name = ((Element) node).getAttribute("name"); if (name != null) { try { Node xml = mxUtils.loadDocument( mxObjectCodec.class.getResource(name).toString()) .getDocumentElement(); if (xml != null) { dec.decode(xml, into); } } catch (Exception e) { System.err.println("Cannot process include: " + name); } } return true; } return false; } /** * Hook for subclassers to pre-process the node for the specified object * and return the node to be used for further processing by * {@link #decode(mxCodec, Node)}. The object is created based on the * template in the calling method and is never null. * * This implementation returns the input node. The return value of this * function is used in {@link #decode(mxCodec, Node)} to perform the * default decoding into the given object. * * @param dec Codec that controls the decoding process. * @param node XML node to be decoded. * @param obj Object to encode the node into. * @return Returns the node used for the default decoding. */ public Node beforeDecode(mxCodec dec, Node node, Object obj) { return node; } /** * Hook for subclassers to post-process the object after decoding. This * implementation returns the given object without any changes. The return * value of this method is returned to the decoder from * {@link #decode(mxCodec, Node)}. * * @param dec Codec that controls the decoding process. * @param node XML node to be decoded. * @param obj Object that represents the default decoding. * @return Returns the result of the decoding process. */ public Object afterDecode(mxCodec dec, Node node, Object obj) { return obj; }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -