xmladapter4objects.java
来自「Mandarax是一个规则引擎的纯Java实现。它支持多类型的事实和基于反映的规」· Java 代码 · 共 270 行
JAVA
270 行
package org.mandarax.xkb.framework;
/**
* Copyright (C) 1999-2004 Jens Dietrich (mailto:mandarax@jbdietrich.com)
*
* 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 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
*/
import java.beans.BeanInfo;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.jdom.Element;
import org.mandarax.kernel.LogicFactory;
import org.mandarax.xkb.XKBException;
/**
* An adapter class for objects. Strings and primitives are just stringified,
* dates represented by the time as long, classes by the name, and
* beans are handeled via introspection. <p>
* <strong>Warning:</strong> We cannot and do not solve the more general problem of XML object serialization here.
* Instead, this is a 80-20 solution that might work fine for simple object models. For more sophisticated
* object models, you will need to implement your own object adapter. In particular, we do not handle circular
* references.
* <p>
* In the future (once JDK 1.4 is the common platform) we will integrate the new XML serialization mechanism!
* @author <A href="http://www-ist.massey.ac.nz/JBDietrich" target="_top">Jens Dietrich</A>
* @version 3.4 <7 March 05>
* @since 1.6
* @deprecated from v 3.4 - support for new features such as validation will not be added to XKB, please use ZKB instead
*/
public class XMLAdapter4Objects extends CachedXMLAdapter {
public static final String OBJECT = "object";
public static final String DATA = "data";
public static final String OBJECT_TYPE = "object_type";
public static final String STRING = String.class.getName();
public static final String INTEGER = Integer.class.getName();
public static final String BOOLEAN = Boolean.class.getName();
public static final String LONG = Long.class.getName();
public static final String SHORT = Short.class.getName();
public static final String CHARACTER = Character.class.getName();
public static final String BYTE = Byte.class.getName();
public static final String DOUBLE = Double.class.getName();
public static final String FLOAT = Float.class.getName();
public static final String BEAN = "bean";
public static final String PRIMITIVE = "primitive";
public static final String DATE = "date";
public static final String NULL = "null";
public static final String PROPERTIES = "properties";
public static final String PROPERTY_NAME = "property_name";
public static final String BEAN_CLASS = "bean_class";
public static final String CLASS = "class";
/**
* Export an object, i.e., convert it to an element in the DOM.
* @param obj an object
* @param driver the generic driver
* @param cache a cache used in order to associate the same
* id with various occurences of the same object
* @exception an XKBException is thrown if export fails
*/
protected Element _exportObject(Object obj,GenericDriver driver,Map cache) throws XKBException {
boolean debug = LOG_XKB.isDebugEnabled();
Element e = new Element(OBJECT);
// export null, primitives and strings first
if (obj==null) {
e.setAttribute(OBJECT_TYPE,NULL);
return e;
}
if (isSimpleObject(obj)) {
e.setAttribute(DATA,obj.toString());
e.setAttribute(OBJECT_TYPE,PRIMITIVE);
e.setAttribute(CLASS,obj.getClass().getName());
if (debug) LOG_XKB.debug("Exporting object as primitive - value: " + obj.toString());
return e;
}
// export classes
if (obj instanceof Class) {
e.setAttribute(DATA,((Class)obj).getName());
e.setAttribute(OBJECT_TYPE,CLASS);
if (debug) LOG_XKB.debug("Exporting object as class - value: " + ((Class)obj).getName());
return e;
}
// export dates
if (obj instanceof Date) {
Date date = (Date)obj;
e.setAttribute(DATA,String.valueOf(date.getTime()));
e.setAttribute(OBJECT_TYPE,DATE);
e.setAttribute(CLASS,obj.getClass().getName());
if (debug) LOG_XKB.debug("Exporting object as date - value: " + date.getTime());
return e;
}
// otherwise export object as a bean using introspection
e.setAttribute(OBJECT_TYPE,BEAN);
e.setAttribute(CLASS,obj.getClass().getName());
try {
BeanInfo beanInfo = Introspector.getBeanInfo(obj.getClass(),Object.class);
PropertyDescriptor[] properties = beanInfo.getPropertyDescriptors();
Element eProperties = new Element(PROPERTIES);
if (debug) LOG_XKB.debug("Exporting object as bean - class: " + obj.getClass());
for (int i=0;i<properties.length;i++) {
PropertyDescriptor property = properties[i];
String name = property.getName();
Method getter = property.getReadMethod();
Object[] par = new Object[0];
try {
Object value = getter.invoke(obj,par);
if (debug) LOG_XKB.debug("Exporting property : " + name + " -> " + value);
Element eValue = exportObject(value,driver,cache);
eValue.setAttribute(PROPERTY_NAME,name);
eProperties.addContent(eValue);
}
catch (Exception x) {
// note: we carry on without this property but log the error !
LOG_XKB.error("Cannot write property " + name + " for object " + obj,x);
}
}
e.addContent(eProperties);
}
catch (Exception x) {
throw new XKBException("Export failed: cannot inspect object " + obj);
}
return e;
}
/**
* Build an object from an XML element.
* @param e an element
* @param driver the generic driver
* @param cache a cache used to identify objects that have the same id
* @param lfactory the logic factory used to create objects
* @exception an XKBException is thrown if export fails
*/
protected Object _importObject(Element e,GenericDriver driver,Map cache,LogicFactory lfactory) throws XKBException {
// import null and primitives first
String objType = e.getAttributeValue(OBJECT_TYPE);
if (NULL.equals(objType)) return null;
String className = e.getAttributeValue(CLASS);
String stringified = e.getAttributeValue(DATA);
if (PRIMITIVE.equals(objType)) {
if (STRING.equals(className)) return stringified;
if (BOOLEAN.equals(className)) return Boolean.valueOf(stringified);
if (CHARACTER.equals(className)) return new Character(stringified.charAt(0));
// the numerical types
try {
if (INTEGER.equals(className)) return Integer.valueOf(stringified);
if (BYTE.equals(className)) return Byte.valueOf(stringified);
if (SHORT.equals(className)) return Short.valueOf(stringified);
if (LONG.equals(className)) return Long.valueOf(stringified);
if (DOUBLE.equals(className)) return Double.valueOf(stringified);
if (FLOAT.equals(className)) return Float.valueOf(stringified);
}
catch (NumberFormatException x) {
throw new XKBException("Cannot parse " + stringified + " to instanciate " + objType);
}
}
// import classes
if (CLASS.equals(objType)) {
String clazzName = e.getAttributeValue(DATA);
try {
return Class.forName(clazzName);
}
catch (Exception x) {
throw new XKBException("Cannot find class named " + clazzName);
}
}
// import dates
if (DATE.equals(objType)) {
long time = 0;
try {
time = Long.parseLong(e.getAttributeValue(DATA));
}
catch (NumberFormatException x) {
throw new XKBException("Cannot interprete " + time + " as a date (cannot parse long)");
}
if (className == null) return new Date(time);
if (java.sql.Date.class.getName().equals(className)) return new java.sql.Date(time);
if (java.sql.Time.class.getName().equals(className)) return new java.sql.Time(time);
if (java.sql.Timestamp.class.getName().equals(className)) return new java.sql.Timestamp(time);
LOG_XKB.warn("Don't know implementation class " + className +" for date, use java.util.Date");
return new Date(time);
}
// import beans
if (BEAN.equals(objType)) {
Object bean = null;
try {
Class clazz = Class.forName(className);
bean = clazz.newInstance();
BeanInfo beanInfo = Introspector.getBeanInfo(clazz,Object.class);
PropertyDescriptor[] properties = beanInfo.getPropertyDescriptors();
List eProperties = e.getChild(PROPERTIES).getChildren();
PropertyDescriptor property = null;
Object[] par = new Object[1];
for (Iterator it = eProperties.iterator();it.hasNext();) {
property = null;
Element eProperty = (Element)it.next();
String name = eProperty.getAttributeValue(PROPERTY_NAME);
// look up properties
for (int i=0;i<properties.length;i++) {
if (properties[i].getName().equals(name)) property = properties[i];
}
// if no property has been found, warn but continue
if (property==null) LOG_XKB.warn("Introspection problem - cannot locate property " + name + " in class " + clazz);
else {
try {
Method setter = property.getWriteMethod();
par[0] = importObject(eProperty,driver,cache,lfactory);
setter.invoke(bean,par);
}
catch (Exception x) {
// note: we carry on without this property but log the error !
LOG_XKB.error("Cannot set property " + name + " for object " + bean,x);
}
}
}
return bean;
}
catch (Exception x) {
LOG_XKB.error("Cannot import bean of class " + className + " from data " + bean,x);
throw new XKBException("Cannot import object " + bean);
}
}
else throw new XKBException("Cannot import object from " + e.toString() + " - it is neither marked as a primitive nor as a bean");
}
/**
* Get the name of the associated tag (element).
* @return a string
*/
public String getTagName() {
return OBJECT;
}
/**
* Get the kind of object the adapter can export/import.
* @return a string
*/
public String getKindOfObject() {
return GenericDriver.OBJECT;
}
/**
* Indicates whether the object represents a primitive or string.
* @return a boolean
* @param obj an object
*/
private boolean isSimpleObject(Object obj) {
return (obj instanceof String) ||
(obj instanceof Number) ||
(obj instanceof Boolean);
}
}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?