hi, guys,
I am a hibernate lover from vesion 2.
per the hibernate 3 has been realesed, I found net.sf.hibernate.xml
pacakage and XMLDatabinder class disappeared.
I think it should be useful sometimes and it is better to keep this
functionality.
moreover, attached my own ReverseXMLDatabinder.java, it convert xml to
hibernate java object.
it is working for 2.14
hope a little help.
glen
package export.util;
import net.sf.hibernate.HibernateException;
import net.sf.hibernate.MappingException;
import net.sf.hibernate.collection.CollectionPersister;
import net.sf.hibernate.engine.SessionFactoryImplementor;
import net.sf.hibernate.engine.SessionImplementor;
import net.sf.hibernate.metadata.ClassMetadata;
import net.sf.hibernate.persister.ClassPersister;
import net.sf.hibernate.type.ComponentType;
import net.sf.hibernate.type.DateType;
import net.sf.hibernate.type.PersistentCollectionType;
import net.sf.hibernate.type.TimestampType;
import net.sf.hibernate.type.Type;
import org.apache.commons.lang.builder.EqualsBuilder;
import org.apache.log4j.Logger;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.dom4j.DocumentHelper;
import export.entity.log.ActionLog;
import java.io.Serializable;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
/**
*
* <ul>
* <li>Convert hibernate generic xml to object with bi-direction link as
* hibernate format.
* </ul>
*
* @author
glen.xin.guo@gmail.com
* @version 0.1
*/
public class ReverseXMLDatabinder {
private List objects = new ArrayList();
public Map objectsMap = new HashMap();
private SessionFactoryImplementor factory;
private SessionImplementor session;
private String fullyQualifiedClassName;
private final static Logger log = Logger
.getLogger(ReverseXMLDatabinder.class);
/**
* Public construct.
*
* @param factory
* @param session
*/
public ReverseXMLDatabinder(SessionFactoryImplementor factory,
SessionImplementor session) {
this.factory = factory;
this.session = session;
}
/**
* Return a List container holds object
*
* @return java.util.List
*/
public List getObjects() {
return objects;
}
/*
* get PK of object
*/
private Object getId(Element element, Object parentObj)
throws ClassNotFoundException, HibernateException,
InstantiationException, IllegalAccessException, DBUtilException {
Object id = null;
Class clazz = getClassForElement(element, "class", "package");
ClassPersister persister = getPersister(clazz);
Object obj = null;
//ID (composite ids not supported atm)
Type idType = persister.getIdentifierType();
String idStrValue = element.elementText("id");
//no id property, try composite id
if (idStrValue == null) {
Element compositeIdElement = element.element("composite-id");
if (compositeIdElement != null) {
List propertiesOfCompositeIdElement = compositeIdElement
.elements("property");
int compositeId_size = propertiesOfCompositeIdElement.size();
String[] compositeIdValueStr = new String[compositeId_size];
String[] compositeIdPropertyName = new String[compositeId_size];
for (int i = 0; i < compositeId_size; i++) {
Element propertyOfCompositeIdElement = (Element) propertiesOfCompositeIdElement
.get(i);
compositeIdValueStr[i] = propertyOfCompositeIdElement
.getText();
compositeIdPropertyName[i] = propertyOfCompositeIdElement
.attributeValue("name");
}
Object[] propertyValuesOfCompositeId = new Object[propertiesOfCompositeIdElement
.size()];
Type[] subtypes = ((ComponentType) idType).getSubtypes();
for (int i = 0; i < subtypes.length; i++) {
Type subtype = subtypes[i];
if (!subtype.isEntityType()) {
String valueStr = GetValueStrInCompositeId(
compositeIdValueStr, compositeIdPropertyName,
compositeIdPropertyName[i]);
propertyValuesOfCompositeId[i] = fromXml(subtype,
valueStr);
} else {
//recursion getId
if (parentObj == null) {
Element temp_element = (Element) (propertiesOfCompositeIdElement
.get(i));
Object temp_id = getId(temp_element, null);
Class temp_clazz = getClassForElement(temp_element,
"class", "package");
ClassPersister temp_persister = getPersister(temp_clazz);
//ID (composite ids not supported atm)
Type temp_idType = persister.getIdentifierType();
parentObj = addObjectOrGetExisting(temp_persister,
temp_id, temp_idType, temp_clazz);
}
propertyValuesOfCompositeId[i] = parentObj;
}
}
Class id_clazz = getClassForElement(compositeIdElement,
"class", "");
Object composite_id = id_clazz.newInstance();
((ComponentType) idType).setPropertyValues(composite_id,
propertyValuesOfCompositeId);
id = composite_id;
}
} else {
id = idStrValue;
}
return id;
}
/**
* Main function method to process data xml and convert it to object within
* hibernate session!
*
* @param xmlData
* @throws ClassNotFoundException
* @throws HibernateException
* @throws InstantiationException
* @throws IllegalAccessException
* @throws DocumentException
* @throws DBUtilException
*/
public void fromXML(String xmlData) throws ClassNotFoundException,
HibernateException, InstantiationException, IllegalAccessException,
DocumentException, DBUtilException {
List xmlValidationErrorsList = new ArrayList();
SAXReader reader = new SAXReader();
Document doc = DocumentHelper.parseText(xmlData);
Element root = doc.getRootElement();
Iterator iter = root.elementIterator();
while (iter.hasNext()) {
Element element = (Element) iter.next();
Object id = getId(element, null);
Class clazz = getClassForElement(element, "class", "package");
ClassPersister persister = getPersister(clazz);
Object obj = null;
//ID (composite ids not supported atm)
Type idType = persister.getIdentifierType();
obj = addObjectOrGetExisting(persister, id, idType, clazz);
//PROPERTIES
List properties = element.elements("property");
if (properties.size() > 0)
log.debug("processing properties for "
+ fullyQualifiedClassName);
for (int i = 0; i < properties.size(); i++) {
Element propertyElement = (Element) properties.get(i);
//log.debug("###############################");
//log.debug("time is "+propertyElement.attributeValue("time"));
setProperty(obj, persister, propertyElement);
}
//COLLECTIONS
List collections = element.elements("collection");
if (collections.size() > 0)
log.debug("processing collections for "
+ fullyQualifiedClassName);
for (int i = 0; i < collections.size(); i++) {
Element collectionElement = (Element) collections.get(i);
setProperty(obj, persister, collectionElement);
}
}
}
private String GetValueStrInCompositeId(String[] compositeIdValueStr,
String[] compositeIdPropertyName, String propertyName) {
String value = "";
for (int i = 0; i < compositeIdPropertyName.length; i++) {
if (propertyName != null
&& propertyName.equals(compositeIdPropertyName[i])) {
value = value.concat(compositeIdValueStr[i]);
break;
}
}
return value;
}
private Class getClassForElement(Element element,
String classAttributeName, String packageAttributeName)
throws ClassNotFoundException, DBUtilException {
String className = element.attributeValue(classAttributeName);
/*
* if(className == null){ log.fatal("className is null. check
* Bi-direction!!!"); throw new DBUtilException("className is null.
* check Bi-direction!!!"); }
*/
fullyQualifiedClassName = "";
if (packageAttributeName != null && packageAttributeName.length() > 0) {
String packageName = element.attributeValue(packageAttributeName);
fullyQualifiedClassName += packageName + ".";
}
fullyQualifiedClassName += className;
Class clazz = Class.forName(fullyQualifiedClassName);
return clazz;
}
/*
* add Object Or Get Existing from object map
*/
private Object addObjectOrGetExisting(ClassPersister persister,
Object rawIdValue, Type idType, Class clazz)
throws HibernateException, IllegalAccessException,
InstantiationException, DBUtilException {
if (rawIdValue == null) {
return clazz.newInstance();
}
Object obj = null;
if (persister.hasIdentifierPropertyOrEmbeddedCompositeIdentifier()) {
Object idValue = null;
ClassAndIdPair classAndIdPair = null;
if (persister.hasIdentifierProperty()) {
if (persister.getIdentifierType() instanceof ComponentType) {
idValue = rawIdValue;
} else {
idValue = fromXml(idType, (String) rawIdValue);
}
}
//???????????????????/
//else if (persister.getIdentifierType() instanceof ComponentType)
//{
// idValue = rawIdValue;
//}
classAndIdPair = new ClassAndIdPair(clazz, idValue);
obj = objectsMap.get(classAndIdPair);
if (obj == null) {
if (persister.hasIdentifierProperty()) {
log.debug("Load class " + fullyQualifiedClassName);
try {
obj = session.get(clazz, (Serializable) idValue);
//not in DB, so create new obj
if (obj == null) {
obj = session.instantiate(clazz,
(Serializable) idValue);
log.debug("class " + fullyQualifiedClassName
+ " not found! create new!");
}
} catch (net.sf.hibernate.TransientObjectException e) {
log.debug("NO WORRIES??? net.sf.hibernate.TransientObjectException: "
+ e.getMessage());
// not in DB, so create new obj
if (obj == null) {
obj = session.instantiate(clazz,
(Serializable) idValue);
log.debug("class " + fullyQualifiedClassName
+ " not found! create new!");
}
}
if (session.contains(obj))
log.debug("fullyQualifiedClassName: "
+ fullyQualifiedClassName + " in DB!");
} else {
log.debug("it is woking? for NO PK class");
obj = clazz.newInstance();
}
/*
* ? should move to line 271? what is useful? if
* (persister.hasIdentifierProperty()) { log.info("it is
* woking?"); persister.setIdentifier(obj,
* (Serializable)idValue); }
*/
objects.add(obj);
objectsMap.put(classAndIdPair, obj);
}
} else {
//? just to be on the safe side
obj = clazz.newInstance();
}
return obj;
}
private void setProperty(Object obj, ClassPersister persister,
Element propertyElement) throws HibernateException,
ClassNotFoundException, IllegalAccessException,
InstantiationException, DBUtilException {
String propertyName = propertyElement.attributeValue("name");
String propertyValueStr = propertyElement.getText();
Type type = persister.getPropertyType(propertyName);
if (type.isPersistentCollectionType()) {
log.debug("Load collection " + propertyName);
Collection collection = (Collection) ((ClassMetadata) persister)
.getPropertyValue(obj, propertyName);
if (collection != null)
log.debug(propertyName + " collection size load from DB: "
+ collection.size());
if (collection == null) {
log.debug("colletion is null");
CollectionPersister collectionPersister = session.getFactory()
.getCollectionPersister(
((PersistentCollectionType) type).getRole());
collection = (Collection) ((PersistentCollectionType) type)
.instantiate(session, collectionPersister);
//collection =
// (Collection)((PersistentCollectionType)type).getCollection(persister.getIdentifier(obj),
// obj, session);
//latest Hibernate code seems to be broken, a hack:
if (collection instanceof java.util.Set) {
collection = new java.util.HashSet();
} else if (collection instanceof java.util.List) {
collection = new java.util.ArrayList();
}
((ClassMetadata) persister).setPropertyValue(obj, propertyName,
collection);
}
List elements = propertyElement.elements("element");
log.debug(propertyName + " element size from xml is: "
+ elements.size());
boolean deleteFlag = true;
/*
* for the collection of actionlogs and sadreasons, deleteFlag will
* be always false forever!
*/
if (propertyName.equalsIgnoreCase("actionlogs"))
deleteFlag = false;
if (deleteFlag && propertyName.equalsIgnoreCase("actionlogs")) {
throw new DBUtilException("delete flag is wrong !");
}
//if no child in collection, so clear all
if (elements.size() == 0 && deleteFlag)
collection.clear();
String elemXml[] = new String[elements.size()];
for (int i = 0; i < elements.size(); i++) {
Element elementElement = (Element) elements.get(i);
Object elementId = getId(elementElement, obj);
Class elementClazz = getClassForElement(elementElement,
"class", "package");
ClassPersister elementPersister = getPersister(elementClazz);
Type elementIdType = elementPersister.getIdentifierType();
Object element = addObjectOrGetExisting(elementPersister,
elementId, elementIdType, elementClazz);
if (deleteFlag && !propertyName.equalsIgnoreCase("actionlogs"))
elemXml[i] = parseStr(element.toString());
/*if (propertyName.equalsIgnoreCase("actionlogs")
&& element instanceof ActionLog) {
ActionLog al = (ActionLog) element;
if (al.getComp_id().getTime() == null) {
log.info("ActionLogtime is null!!!!!!!!!!!!");
al.getComp_id().setTime(
Calendar.getInstance().getTime());
}
}*/
if (collection.add(element))
log.debug("add new element done: " + element.toString());
}
/*
* for delete orphan child in collection except SadReason,Actionlog!
*/
if (elements.size() < collection.size() && elements.size() != 0
&& deleteFlag) {
log.debug("############################################");
log.debug("###Load collection: " + propertyName);
log.debug("for delete orphan child in collection!");
log
.debug("In xml, "
+ elements.size()
+ " child in should be left in collection after remove!");
Object[] o = collection.toArray();
log.debug("collection size before delete is " + o.length);
long collSizeAfterAdd = collection.size();
for (int j = 0; j < collSizeAfterAdd; j++) {
log.debug("processing NO." + j + " obj in collection!");
boolean found = false;
for (int k = 0; k < elements.size(); k++) {
String str = parseStr(o[j].toString());
log.debug("str length: " + str.length());
log.debug("Xml length: " + elemXml[k].length());
//if found in elements,, then keep in collection,
//otherwise, remove from collection
if (str.equalsIgnoreCase(elemXml[k])) {
log.debug("found collection " + j + " in element!");
log.debug("elemStr: " + elemXml[k]);
log.debug("collstr: " + str);
found = true;
break;
}
}
if (!found) {
log.debug("remove " + j + " child!");
log.debug("delete obj in DB: "
+ parseStr(o[j].toString()));
collection.remove(o[j]);
}
}
log.debug("after delete child, collection size: "
+ collection.size());
if (collection.size() != elements.size()) {
log.fatal("###############delete orphan children is wrong !");
throw new DBUtilException(
"delete orphan children is wrong !");
}
}
if (collection.size() != elements.size() && deleteFlag) {
log
.fatal("###############processing collection wrong!");
throw new DBUtilException("processing collection wrong!");
}
} else if (type.isEntityType()) {
//To be ensure!!!!
String entityIdStr = propertyElement.elementText("id");
//String entityIdStr = propertyElement.attributeValue("id");
if (entityIdStr != null) {
Class entityClazz = getClassForElement(propertyElement, "type",
null);
ClassPersister entityPersister = getPersister(entityClazz);
Type entityIdType = entityPersister.getIdentifierType();
Object propertyValue = addObjectOrGetExisting(persister,
entityIdStr, entityIdType, entityClazz);
((ClassMetadata) persister).setPropertyValue(obj, propertyName,
propertyValue);
}
} else {
Object propertyValue = fromXml(type, propertyValueStr);
((ClassMetadata) persister).setPropertyValue(obj, propertyName,
propertyValue);
}
}
/**
* @todo: correct TimestampType and DateType's fromString() to use the same format of the corresponding toString()
*/
private Object fromXml(Type idType, String str) throws HibernateException,
DBUtilException {
if (idType instanceof TimestampType) {
if (str.length() == 0)
throw new DBUtilException("Timestamp is null! ");
try {
if (str != null && str.trim().length() > 0) {
//1989-06-04 11:11:11.0
log.debug("TimestampType ActionLog time: " + new SimpleDateFormat("dd MMMM yyyy HH:mm:ss")
.parse(str));
return new SimpleDateFormat("dd MMMM yyyy HH:mm:ss")
.parse(str);
} else {
return null;
}
} catch (ParseException e) {
return null;
}
} else if (idType instanceof DateType) {
try {
if (str != null && str.trim().length() > 0) {
log.debug("Date ActionLog Time: "
+ new SimpleDateFormat("dd MMMM yyyy").parse(str));
return new SimpleDateFormat("dd MMMM yyyy").parse(str);
} else {
return null;
}
} catch (ParseException e) {
return null;
}
} else {
return idType.fromString(str);
}
}
private ClassPersister getPersister(Class clazz) throws MappingException {
return factory.getPersister(clazz);
}
//for get value part from class.toString
private String parseStr(String str) {
str = str.trim();
int index = str.indexOf("[");
str = str.substring(index);
index = str.indexOf("[");
str = str.substring(index + 1);
index = str.indexOf("[");
return str.substring(index);
}
private static final class ClassAndIdPair {
public Class clazz;
public Object id;
public ClassAndIdPair(Class clazz, Object id) {
this.clazz = clazz;
this.id = id;
}
public boolean equals(Object obj) {
return EqualsBuilder.reflectionEquals(this, obj);
}
public int hashCode() {
return clazz.getName().hashCode()
+ (id != null ? id.hashCode() : 0);
}
}
}