001 /* 002 @license.text@ 003 */ 004 package biz.hammurapi.xml.dom; 005 006 import java.lang.reflect.Field; 007 import java.lang.reflect.Method; 008 import java.lang.reflect.Modifier; 009 import java.util.HashMap; 010 import java.util.HashSet; 011 import java.util.Map; 012 import java.util.Set; 013 014 import org.w3c.dom.Element; 015 016 import biz.hammurapi.convert.Converter; 017 018 /** 019 * @author Pavel Vlasov 020 * 021 * @version $Revision: 1.4 $ 022 */ 023 public class BeanDomSerializer { 024 private class StackEntry { 025 long counter; 026 027 private class IdentityWrapper { 028 Object o; 029 030 public IdentityWrapper(Object o) { 031 this.o=o; 032 } 033 034 public int hashCode() { 035 return o.hashCode(); 036 } 037 038 public boolean equals(Object obj) { 039 return obj instanceof IdentityWrapper && o==((IdentityWrapper) obj).o; 040 } 041 } 042 043 Map identityMap=new HashMap(); 044 Map referenceMap=new HashMap(); 045 046 Long getReference(Object o) { 047 if (o instanceof Number || o instanceof String) { 048 return (Long) referenceMap.get(o); 049 } 050 051 return (Long) identityMap.get(new IdentityWrapper(o)); 052 } 053 054 long addReference(Object o) { 055 if (o instanceof Number || o instanceof String) { 056 Long ref=(Long) referenceMap.get(o); 057 if (ref==null) { 058 long next=counter++; 059 referenceMap.put(o, new Long(next)); 060 return next; 061 } 062 063 return ref.longValue(); 064 } 065 066 IdentityWrapper iw = new IdentityWrapper(o); 067 068 Long ref=(Long) identityMap.get(iw); 069 if (ref==null) { 070 long next=counter++; 071 identityMap.put(iw, new Long(next)); 072 return next; 073 } 074 075 return ref.longValue(); 076 } 077 } 078 079 private static ThreadLocal stack=new ThreadLocal(); 080 081 private Set badMethods=new HashSet(); 082 083 public DomSerializable convert(final Object object, final Converter master) { 084 if (object!=null) { 085 return new DomSerializable() { 086 087 public void toDom(Element holder) { 088 if (object instanceof Class) { 089 holder.appendChild(holder.getOwnerDocument().createTextNode(((Class) object).getName())); 090 return; 091 } 092 093 StackEntry sEntry=(StackEntry) stack.get(); 094 boolean clean = sEntry==null; 095 if (clean) { 096 sEntry=new StackEntry(); 097 stack.set(sEntry); 098 } 099 100 try { 101 102 Long refId=sEntry.getReference(object); 103 if (refId!=null) { 104 holder.setAttribute("refid", refId.toString()); 105 return; 106 } 107 108 long nextCounter = sEntry.addReference(object); 109 //System.out.println("New id: "+nextCounter); 110 holder.setAttribute("id", String.valueOf(nextCounter)); 111 112 holder.setAttribute("type", object.getClass().getName()); 113 holder.appendChild(holder.getOwnerDocument().createTextNode(object.toString())); 114 115 if (master!=null) { 116 Class beanClass=object.getClass(); 117 final Object[] args = new Object[] {}; 118 Method[] methods = beanClass.getMethods(); 119 for (int i=0; i<methods.length; i++) { 120 // getXXX() methods. Object.getClass() is not included. 121 Method method = methods[i]; 122 if (!(void.class.equals(method.getReturnType())) 123 && Modifier.isPublic(method.getModifiers()) 124 && !Modifier.isAbstract(method.getModifiers()) 125 && !(method.getDeclaringClass().equals(Object.class)) 126 && !Modifier.isStatic(method.getModifiers()) 127 && method.getName().startsWith("get") 128 && method.getParameterTypes().length==0 129 && !isBad(method)) { 130 try { 131 Object value=method.invoke(object, args); 132 if (value!=object) { 133 DomSerializable vds=(DomSerializable) master.convert(value, DomSerializable.class, null); 134 if (vds!=null) { 135 Element ve=holder.getOwnerDocument().createElement(method.getName().substring(3)); 136 holder.appendChild(ve); 137 vds.toDom(ve); 138 } 139 } 140 } catch (Exception e) { 141 synchronized (badMethods) { 142 badMethods.add(method); 143 } 144 handleAccessError(holder, method, e, master); 145 } 146 } 147 } 148 149 Field[] fields = beanClass.getFields(); 150 for (int i=0; i<fields.length; i++) { 151 Field field = fields[i]; 152 if (!Modifier.isStatic(field.getModifiers()) && Modifier.isPublic(field.getModifiers())) { 153 try { 154 Object value=field.get(object); 155 DomSerializable vds=(DomSerializable) master.convert(value, DomSerializable.class, null); 156 if (vds!=null) { 157 Element ve=holder.getOwnerDocument().createElement(field.getName()); 158 holder.appendChild(ve); 159 vds.toDom(ve); 160 } 161 } catch (Exception e) { 162 handleAccessError(holder, field, e, master); 163 } 164 } 165 } 166 } 167 } finally { 168 if (clean) { 169 stack.set(null); 170 } 171 } 172 } 173 174 private boolean isBad(Method method) { 175 synchronized (badMethods) { 176 return badMethods.contains(method); 177 } 178 } 179 }; 180 } 181 182 return null; 183 } 184 185 private void handleAccessError(Element holder, java.lang.reflect.Member member, Throwable e, Converter master) { 186 Element ee=holder.getOwnerDocument().createElement("access-error"); 187 holder.appendChild(ee); 188 ee.setAttribute("member", member.toString()); 189 DomSerializable eds=(DomSerializable) master.convert(e, DomSerializable.class, null); 190 eds.toDom(ee); 191 } 192 }