package com.cosylab.cdb.jdal.hibernate; import java.lang.reflect.Array; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Arrays; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.logging.Logger; import org.w3c.dom.Element; import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import alma.acs.util.XmlNormalizer; import com.cosylab.cdb.jdal.DAOImpl; import com.cosylab.cdb.jdal.XMLTreeNode; /******************************************************************************* * ALMA - Atacama Large Millimiter Array * (c) European Southern Observatory, 2002 * Copyright by ESO (in the framework of the ALMA collaboration) * and Cosylab 2002, All rights reserved * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * DOM-like Java class introspector. * @author msekoranja */ public class DOMJavaClassIntrospector { public static final char PATH_SEPARATOR = '/'; public static final String SUBNODES_MAP_NAME = "_"; public static final String SUBNODES_MAP_NAME_ALTERNATIVE = "MAP_"; public static Object getNode(String path, Object rootNode) { // System.out.println("Getting node "+path+" for rootNode: "+rootNode.getClass().getName()); // return array of all subnodes if (path.length() == 0) return rootNode; // remove trailing slashes, we are quite tolerant to additional slashes if (path.charAt(0) == '/') return getNode(path.substring(1), rootNode); int pos = path.indexOf('/'); if (pos == -1) return getChild(path, rootNode); if (rootNode instanceof alma.TMCDB.maci.LoggingConfig) { // System.out.println("Getting child for LoggingConfig"); return getChild(path, rootNode); } String parent = path.substring(0, pos); String subpath = path.substring(pos+1, path.length()); Object subnode = getNode(parent, rootNode); if (subnode != null) return getNode(subpath, subnode); // not found return null; } public static class NodeAndMutator { public Object node; public Method mutator; public NodeAndMutator(Object node, Method mutator) { this.node = node; this.mutator = mutator; } } public static NodeAndMutator getRecursiveMutatorMethod(String path, Object rootNode) { return getRecursiveMutatorMethod(path, rootNode, null); } public static NodeAndMutator getRecursiveMutatorMethod(String path, Object rootNode, XMLSaver parentSaver) { //System.out.println("Getting recursive node "+path+" for rootNode: "+rootNode.getClass().getName()); if (path.length() == 0) throw new IllegalArgumentException("empty path"); // remove trailing slashes, we are quite tolerant to additional slashes if (path.charAt(0) == '/') return getRecursiveMutatorMethod(path.substring(1), rootNode, parentSaver); if (rootNode instanceof XMLSaver) parentSaver = (XMLSaver)rootNode; int pos = path.indexOf('/'); if (pos == -1) return getMutatorMethod(path, rootNode, parentSaver); if (rootNode instanceof alma.TMCDB.maci.LoggingConfig) return getMutatorMethod(path, rootNode, null); String parent = path.substring(0, pos); String subpath = path.substring(pos+1, path.length()); Object subnode = getNode(parent, rootNode); if (subnode != null) return getRecursiveMutatorMethod(subpath, subnode, parentSaver); // not found return null; } public static final Method getAccessorMethod(Class type, String fieldName) { try { String accessorMethodName = "get" + Character.toUpperCase(fieldName.charAt(0)) + fieldName.substring(1); return type.getMethod(accessorMethodName, (Class[])null); } catch (NoSuchMethodException e) { } try { String accessorMethodName = "is" + Character.toUpperCase(fieldName.charAt(0)) + fieldName.substring(1); return type.getMethod(accessorMethodName, (Class[])null); } catch (NoSuchMethodException e) { } return null; } public static final Method getMutatorMethod(Class type, String fieldName) { String mutatorMethodName = "set" + Character.toUpperCase(fieldName.charAt(0)) + fieldName.substring(1); Method[] methods = type.getMethods(); for (Method method : methods) if (method.getName().equals(mutatorMethodName)) return method; return null; } public static Object getChild(String name, Object node) { synchronized (node) { //System.out.println("Getting child '"+name+"' for node "+node.getClass().getName()); if (node instanceof DAOImpl) { return (XMLTreeNode)(((DAOImpl)node).getRootNode().getNodesMap().get(name)); } if (node instanceof XMLTreeNode) { Object n = (XMLTreeNode)(((XMLTreeNode)node).getNodesMap().get(name)); if (n != null) return n; else return ((XMLTreeNode)node).getFieldMap().get(name); } else if (node instanceof Map) { Map map = (Map)node; if (map.containsKey(name)) return map.get(name); // not found return null; } else if (node instanceof Element) { // check attribute Element element = (Element)node; if (element.hasAttribute(name)) return element.getAttribute(name); // check element NodeList nodeList = element.getElementsByTagName(name); if (nodeList.getLength() > 0) return (Element)nodeList.item(0); // only digit is not allowed if (name.length() <= 1) return null; // "<name><index>" support for XML sequences, where index > 0 // ends with digit? int pos = name.length()-1; if (Character.isDigit(name.charAt(pos))) { pos--; // extract digit while (Character.isDigit(name.charAt(pos))) pos--; // point to the first digit pos++; String dig = name.substring(pos); name = name.substring(0, pos); try { int ix = Integer.parseInt(dig); if (ix > 0) { nodeList = element.getElementsByTagName(name); if (nodeList.getLength() > ix) { return (Element)nodeList.item(ix); } else return null; // index out of range or no such elements } else return null; // ix <= 0 } catch (Throwable th) { // bad index return null; } } else return null; // does not end with digit } else { Field field = null; final Class nodeType = node.getClass(); Class type = nodeType; while (field == null && type != null) { try { field = type.getDeclaredField(name); } catch (NoSuchFieldException e) { /* noop */ } type = type.getSuperclass(); } if (field != null) { if (name.equals(SUBNODES_MAP_NAME) || name.equals(SUBNODES_MAP_NAME_ALTERNATIVE)) { // this will work only on public fields try { return field.get(node); } catch (IllegalAccessException e) { // failed to access the field return null; } } else { // using accessor try { Method accessorMethod = getAccessorMethod(nodeType, name); Object retVal = accessorMethod.invoke(node, (Object[])null); // @todo TODO now we consider null retVal as non-existant field return retVal; } catch (Throwable th) { // failed to access the field return null; } } } else if (!name.equals(SUBNODES_MAP_NAME) && !name.equals(SUBNODES_MAP_NAME_ALTERNATIVE)) { // check extra data if (node instanceof ExtraDataFeature) { Element extraData = ((ExtraDataFeature)node).getExtraData(); if (extraData != null) { Object viaExtra = getChild(name, extraData); if (viaExtra != null) return viaExtra; } } // check for subnodesMap map Object subnodesMap = getChild(SUBNODES_MAP_NAME, node); if (subnodesMap instanceof Map) { Object obj = ((Map)subnodesMap).get(name); if (obj != null) return obj; } subnodesMap = getChild(SUBNODES_MAP_NAME_ALTERNATIVE, node); if (subnodesMap instanceof Map) { Object obj = ((Map)subnodesMap).get(name); if (obj != null) return obj; } // not in map return null; } // not found return null; } } } public interface XMLSaver { void save(); void save(String xml); } public static class XMLTreeNodeSetter { private final String name; private final Map map; private final XMLSaver parentSaver; public XMLTreeNodeSetter(String name, Map map, XMLSaver parentSaver) { this.name = name; this.map = map; this.parentSaver = parentSaver; } public void setField(String value) { map.put(name, value); if (parentSaver != null) parentSaver.save(); } } public static NodeAndMutator getMutatorMethod(String name, Object node, XMLSaver parentSaver) { //System.out.println("Getting setter '"+name+"' for node "+node.getClass().getName()); if (node instanceof XMLTreeNode) { XMLTreeNode treeNode = (XMLTreeNode)node; if (!treeNode.getFieldMap().containsKey(name)) return null; XMLTreeNodeSetter setterObject = new XMLTreeNodeSetter(name, treeNode.getFieldMap(), parentSaver); return new NodeAndMutator(setterObject, getMutatorMethod(setterObject.getClass(), "field")); } else { Field field = null; final Class nodeType = node.getClass(); Class type = nodeType; while (field == null && type != null) { try { field = type.getDeclaredField(name); } catch (NoSuchFieldException e) { /* noop */ } type = type.getSuperclass(); } if (field != null) { // using mutator return new NodeAndMutator(node, getMutatorMethod(nodeType, name)); } // not found return null; } } /* public static String[] getChildren(Object node) { if (node instanceof Map) return getSubnodes(node); else if (node instanceof Element) { // TODO return null; } else return getFields(node); } */ public static String[] getAccessibleFields(Object node, boolean primitivesOnly) { Set<String> subnodes = new LinkedHashSet<String>(); final Class nodeType = node.getClass(); Class type = nodeType; while (type != null) { Field[] fields = type.getDeclaredFields(); for (Field field : fields) { boolean isPrimitive = isPrimitive(field.getType()); if ((isPrimitive ^ !primitivesOnly) && getAccessorMethod(nodeType, field.getName()) != null) { // do not add null non-primitives check if (isPrimitive || getChild(field.getName(), node) != null) subnodes.add(field.getName()); } } type = type.getSuperclass(); } // and subnodesMap map if (!primitivesOnly) { Object subnodesMap = getChild(SUBNODES_MAP_NAME, node); if (subnodesMap instanceof Map) { Set keySet = ((Map)subnodesMap).keySet(); for (Object key : keySet) subnodes.add(key.toString()); } subnodesMap = getChild(SUBNODES_MAP_NAME_ALTERNATIVE, node); if (subnodesMap instanceof Map) { Set keySet = ((Map)subnodesMap).keySet(); for (Object key : keySet) subnodes.add(key.toString()); } } return subnodes.toArray(new String[subnodes.size()]); } public static void getAccessibleFieldsObjects(Object node, boolean primitivesOnly, ArrayList<NamedObject> subnodes) { final Class nodeType = node.getClass(); Class type = nodeType; while (type != null) { Field[] fields = type.getDeclaredFields(); for (Field field : fields) { boolean isPrimitive = isPrimitive(field.getType()); if ((isPrimitive ^ !primitivesOnly) && getAccessorMethod(nodeType, field.getName()) != null) { // do not add null non-primitives check Object child = getChild(field.getName(), node); if (isPrimitive || child != null) subnodes.add(new NamedObject(field.getName(), child)); } } type = type.getSuperclass(); } // and subnodesMap map if (!primitivesOnly) { Object subnodesMap = getChild(SUBNODES_MAP_NAME, node); if (subnodesMap instanceof Map) { Map map = (Map)subnodesMap; Set keySet = map.keySet(); for (Object key : keySet) subnodes.add(new NamedObject(key.toString(), map.get(key))); } subnodesMap = getChild(SUBNODES_MAP_NAME_ALTERNATIVE, node); if (subnodesMap instanceof Map) { Map map = (Map)subnodesMap; Set keySet = map.keySet(); for (Object key : keySet) subnodes.add(new NamedObject(key.toString(), map.get(key))); } } } public static String[] getElementFields(Object node) { Set<String> subnodes = new LinkedHashSet<String>(); final Class nodeType = node.getClass(); Class type = nodeType; while (type != null) { Field[] fields = type.getDeclaredFields(); for (Field field : fields) { boolean isPrimitive = isPrimitive(field.getType()); if (!isPrimitive && getAccessorMethod(nodeType, field.getName()) != null) { // do not add null elements check if (getChild(field.getName(), node) != null) subnodes.add(field.getName()); } } type = type.getSuperclass(); } Object subnodesMap = getChild(SUBNODES_MAP_NAME, node); if (subnodesMap instanceof InternalElementsMap) { Set keySet = ((Map)subnodesMap).keySet(); for (Object key : keySet) subnodes.add(key.toString()); } subnodesMap = getChild(SUBNODES_MAP_NAME_ALTERNATIVE, node); if (subnodesMap instanceof InternalElementsMap) { Set keySet = ((Map)subnodesMap).keySet(); for (Object key : keySet) subnodes.add(key.toString()); } return subnodes.toArray(new String[subnodes.size()]); } public static String[] getFields(Object node) { return getFields(node, null, null); } public static String[] getFields(Object node, String nodeName, Logger log) { if (node instanceof Map) return new String[0]; else if (node instanceof Element) { NamedNodeMap attributes = ((Element)node).getAttributes(); int size = attributes.getLength(); String[] retVal = new String[size]; for (int i = 0; i < size; i++) retVal[i] = attributes.item(i).getNodeName(); return retVal; } else { if (node instanceof ExtraDataFeature) { String[] extraFields = null; Element extraData = ((ExtraDataFeature)node).getExtraData(); if (extraData != null) extraFields = getFields(extraData); String[] fields = getAccessibleFields(node, true); if (extraFields == null) return fields; // concat and remove duplicates Set<String> set = new LinkedHashSet<String>(Arrays.asList(fields)); for (String ef : extraFields) if (!set.add(ef)) if (log != null) log.warning("Duplicate field '" + nodeName + "/" + ef +"'."); return set.toArray(new String[0]); } else return getAccessibleFields(node, true); } } public static boolean isPrimitive(Class<?> type) { return type.isPrimitive() || Number.class.isAssignableFrom(type) || type == Boolean.class || type == String.class || type.isArray() || ConvertToPrimitiveFeature.class.isAssignableFrom(type); } public static String[] getSubnodes(Object node) { if (node instanceof alma.TMCDB.maci.ComponentNode) return getAccessibleFields(node, false); if (node instanceof Map && !(node instanceof InternalElementsMap)) { Set<String> subnodes = new LinkedHashSet<String>(); Set keySet = ((Map)node).keySet(); for (Object key : keySet) subnodes.add(key.toString()); return subnodes.toArray(new String[subnodes.size()]); } else return new String[0]; } public static String[] getNodes(Object node) { return getNodes(node, null, null); } public static String[] getNodes(Object node, String nodeName, Logger log) { if (node instanceof DAOImpl) { return getNodes(((DAOImpl)node).getRootNode().getNodesMap()); } else if (node instanceof XMLTreeNode) { return getNodes(((XMLTreeNode)node).getNodesMap()); } else if (node instanceof Map) { Set<String> subnodes = new LinkedHashSet<String>(); Set keySet = ((Map)node).keySet(); for (Object key : keySet) subnodes.add(key.toString()); return subnodes.toArray(new String[subnodes.size()]); } else if (node instanceof Element) { List<String> list = new ArrayList<String>(); for (Node childNode = ((Element)node).getFirstChild(); childNode != null; childNode = childNode.getNextSibling()) { if (childNode.getNodeType() == Element.ELEMENT_NODE) list.add(childNode.getNodeName()); } return list.toArray(new String[list.size()]); } else if (node instanceof ExtraDataFeature) { String[] extraFields = null; Element extraData = ((ExtraDataFeature)node).getExtraData(); if (extraData != null) extraFields = getNodes(extraData); String[] fields = getAccessibleFields(node, false); if (extraFields == null) return fields; // concat and remove duplicates LinkedHashSet<String> set = new LinkedHashSet<String>(Arrays.asList(fields)); for (String ef : extraFields) if (!set.add(ef)) if (log != null) log.warning("Duplicate node '" + nodeName + "/" + ef + "'."); return set.toArray(new String[0]); } else return getAccessibleFields(node, false); } static class NamedObject { final String name; final Object obj; NamedObject(String name, Object obj) { this.name = name; this.obj = obj; } } public static NamedObject[] getNodesObjects(Object node, String nodeName, Logger log) { if (node instanceof DAOImpl) { return getNodesObjects(((DAOImpl)node).getRootNode().getNodesMap(), null, null); } else if (node instanceof XMLTreeNode) { return getNodesObjects(((XMLTreeNode)node).getNodesMap(), null, null); } else if (node instanceof Map) { ArrayList<NamedObject> subnodes = new ArrayList<NamedObject>(); Map nodeMap = (Map)node; Set keySet = nodeMap.keySet(); for (Object key : keySet) subnodes.add(new NamedObject(key.toString(), nodeMap.get(key))); return subnodes.toArray(new NamedObject[subnodes.size()]); } else if (node instanceof Element) { ArrayList<NamedObject> list = new ArrayList<NamedObject>(); for (Node childNode = ((Element)node).getFirstChild(); childNode != null; childNode = childNode.getNextSibling()) { if (childNode.getNodeType() == Element.ELEMENT_NODE) list.add(new NamedObject(childNode.getNodeName(), (Element)childNode)); } return list.toArray(new NamedObject[list.size()]); } else { ArrayList<NamedObject> list = new ArrayList<NamedObject>(); if (node instanceof ExtraDataFeature) { NamedObject[] extraFields = null; Element extraData = ((ExtraDataFeature)node).getExtraData(); if (extraData != null) extraFields = getNodesObjects(extraData, null, null); getAccessibleFieldsObjects(node, false, list); if (extraFields != null) { for (NamedObject no : extraFields) list.add(no); } } else getAccessibleFieldsObjects(node, false, list); return list.toArray(new NamedObject[list.size()]); } } public static String[] getElements(Object node) { return getElements(node, null, null); } // element = internal node (excluding hierarchy) public static String[] getElements(Object node, String nodeName, Logger log) { if (node instanceof DAOImpl) { return getNodes(((DAOImpl)node).getRootNode().getNodesMap()); } else if (node instanceof XMLTreeNode) { return getNodes(((XMLTreeNode)node).getNodesMap()); } else if (node instanceof Map) { if (node instanceof InternalElementsMap) { Set<String> subnodes = new LinkedHashSet<String>(); Set keySet = ((Map)node).keySet(); for (Object key : keySet) subnodes.add(key.toString()); return subnodes.toArray(new String[subnodes.size()]); } else return new String[0]; } else if (node instanceof Element) { List<String> list = new ArrayList<String>(); for (Node childNode = ((Element)node).getFirstChild(); childNode != null; childNode = childNode.getNextSibling()) { if (childNode.getNodeType() == Element.ELEMENT_NODE) list.add(childNode.getNodeName()); } return list.toArray(new String[list.size()]); } else if (node instanceof ExtraDataFeature) { String[] extraFields = null; Element extraData = ((ExtraDataFeature)node).getExtraData(); if (extraData != null) extraFields = getElements(extraData); String[] fields = getElementFields(node); if (extraFields == null) return fields; // concat and remove duplicates Set<String> set = new LinkedHashSet<String>(Arrays.asList(fields)); for (String ef : extraFields) if (!set.add(ef)) if (log != null) log.warning("Duplicate element '" + nodeName + "/" + ef + "'."); return set.toArray(new String[0]); } else return getElementFields(node); } public static boolean isMapSubnode(String name, Object parentNode) { // RootMap is a special case if (parentNode instanceof RootMap) return false; else if (parentNode instanceof Map) return true; else { Object subnodesMap = getChild(SUBNODES_MAP_NAME, parentNode); if (subnodesMap instanceof Map) if (((Map)subnodesMap).containsKey(name)) return true; subnodesMap = getChild(SUBNODES_MAP_NAME_ALTERNATIVE, parentNode); if (subnodesMap instanceof Map) if (((Map)subnodesMap).containsKey(name)) return true; return false; } } public static String getNodeXMLName(final String name, final Object node) { if (node instanceof NameOverrideFeature) { final String overrideName = ((NameOverrideFeature)node).getNameOverride(); return overrideName != null ? overrideName : name; } else return name; } public static String getRootNodeXMLName(final String name, final Object node) { if (node instanceof RootNameOverrideFeature) { final String overrideName = ((RootNameOverrideFeature)node).getRootNameOverride(); if (overrideName != null) return overrideName; } return getNodeXMLName(name, node); } public static String toXML(String name, Object node) { return toXML(name, node, null, null); } public static String toXML(String name, Object node, String nodeName, Logger log) { // to confirm w/ XML naming if (Character.isDigit(name.charAt(0))) name = "id" + name; // ugly hack else if (name.charAt(0) == '*') name = "_"; // not nice, but adds DAO support if (node instanceof DAOImpl) return ((DAOImpl)node).getRootNode().toString(false); StringBuffer buffer = new StringBuffer(); buffer.append('<').append(name); // RH: Define the amb ns prefix, if it is needed. Otherwise the // OpticalTelescope component fails. if (name.startsWith("amb:")) buffer.append(" xmlns:amb=\"urn:schemas-cosylab-com:AmbDevice:1.0\" "); String[] fields = getFields(node, nodeName, log); for (String field : fields) { Object fieldValue = handleInfinity(getChild(field, node)); fieldValue = escapeString(fieldValue); if (fieldValue != null) buffer.append(' ').append(field).append('=').append('"').append(fieldValue).append('"'); } buffer.append('>'); /* String[] subnodes = getNodes(node, nodeName, log); for (String subnode : subnodes) { Object childNode = getNode(subnode, node); if (childNode == null) { if (!subnode.equals("ComponentLogger")) System.out.println("Warning: '/' in name, ignored:" + subnode); continue; } boolean dashAsName = false; if (getChild(SUBNODES_MAP_NAME, node) instanceof InternalElementsMap); // TODO SUBNODES_MAP_NAME_ALTERNATIVE else if (isMapSubnode(subnode, node)) { dashAsName = true; Object subsubMap = getChild(SUBNODES_MAP_NAME, childNode); if (subsubMap instanceof Map && ((Map)subsubMap).size() > 0) dashAsName = false; } buffer.append(toXML(getNodeXMLName(dashAsName ? "_" : subnode, childNode), childNode, (nodeName == null) ? null : nodeName + "/" + subnode, log)); } */ NamedObject[] subnodes = getNodesObjects(node, nodeName, log); for (NamedObject namedObject : subnodes) { final String subnode = namedObject.name; final Object childNode = namedObject.obj; // TODO do we really need this? if (subnode.indexOf('/') >= 0) { if (nodeName.endsWith("LoggingConfig") || subnode.equals("ComponentLogger")) { // we allow this, see http://jira.alma.cl/browse/COMP-8302 } else { System.out.println("Warning: '/' in name, ignored:" + subnode); continue; } } boolean dashAsName = false; if (getChild(SUBNODES_MAP_NAME, node) instanceof InternalElementsMap); else if (getChild(SUBNODES_MAP_NAME_ALTERNATIVE, node) instanceof InternalElementsMap); else if (isMapSubnode(subnode, node)) { dashAsName = true; Object subsubMap = getChild(SUBNODES_MAP_NAME, childNode); if (subsubMap instanceof Map && ((Map)subsubMap).size() > 0) dashAsName = false; // check also for alternative if (dashAsName) { subsubMap = getChild(SUBNODES_MAP_NAME_ALTERNATIVE, childNode); if (subsubMap instanceof Map && ((Map)subsubMap).size() > 0) dashAsName = false; } } buffer.append(toXML(getNodeXMLName(dashAsName ? "_" : subnode, childNode), childNode, (nodeName == null) ? null : nodeName + "/" + subnode, log)); } // element value if (node instanceof ElementValueFeature) { String elementValue = ((ElementValueFeature)node).getElementValue(); if (elementValue != null) buffer.append(elementValue); } buffer.append('<').append('/').append(name).append('>'); return buffer.toString(); } public static String stringifyArray(Object array) { return stringifyArray(array, ','); } public static String stringifyArray(Object array, char separator) { Class type = array.getClass(); if (!type.isArray()) throw new IllegalArgumentException("not an array"); Class componentType = type.getComponentType(); if (!componentType.isPrimitive() && componentType != String.class) throw new IllegalArgumentException("not array of a primitive or a string"); StringBuffer buffer = new StringBuffer(); int length = Array.getLength(array); for (int index = 0; index < length - 1; index++) buffer.append(handleInfinity(Array.get(array, index))).append(separator); if (length > 0) buffer.append(handleInfinity(Array.get(array, length - 1))); return buffer.toString(); } public static final Object handleInfinity(final Object value) { if (value instanceof Double) { final double val = ((Double)value).doubleValue(); if (val == Double.POSITIVE_INFINITY) return new Double(Double.MAX_VALUE); else if (val == Double.NEGATIVE_INFINITY) return new Double(Double.MIN_VALUE); return value; } else if (value instanceof Float) { final float val = ((Float)value).floatValue(); if (val == Float.POSITIVE_INFINITY) return new Float(Float.MAX_VALUE); else if (val == Float.NEGATIVE_INFINITY) return new Float(Float.MIN_VALUE); return value; } else return value; } public static final Object escapeString(final Object value) { if (value instanceof String) return XmlNormalizer.normalize((String)value); else return value; } }