PageRenderTime 93ms CodeModel.GetById 20ms RepoModel.GetById 1ms app.codeStats 0ms

/jaxrs/eagledns/src/main/java/se/unlogic/standardutils/xml/XMLGenerator.java

https://bitbucket.org/cprenzberg/resteasy
Java | 349 lines | 205 code | 136 blank | 8 comment | 65 complexity | f6f8c9aa3ec579aa3e69c061fbefee17 MD5 | raw file
  1. /*******************************************************************************
  2. * Copyright (c) 2010 Robert "Unlogic" Olofsson (unlogic@unlogic.se).
  3. * All rights reserved. This program and the accompanying materials
  4. * are made available under the terms of the GNU Lesser Public License v3
  5. * which accompanies this distribution, and is available at
  6. * http://www.gnu.org/licenses/lgpl-3.0-standalone.html
  7. ******************************************************************************/
  8. package se.unlogic.standardutils.xml;
  9. import org.w3c.dom.Document;
  10. import org.w3c.dom.Element;
  11. import se.unlogic.standardutils.annotations.NoAnnotatedFieldsFoundException;
  12. import se.unlogic.standardutils.arrays.ArrayUtils;
  13. import se.unlogic.standardutils.date.DateUtils;
  14. import se.unlogic.standardutils.reflection.ReflectionUtils;
  15. import se.unlogic.standardutils.string.DummyStringyfier;
  16. import se.unlogic.standardutils.string.StringUtils;
  17. import se.unlogic.standardutils.string.Stringyfier;
  18. import java.lang.reflect.Field;
  19. import java.util.ArrayList;
  20. import java.util.Collection;
  21. import java.util.Date;
  22. import java.util.List;
  23. import java.util.concurrent.ConcurrentHashMap;
  24. public class XMLGenerator {
  25. //TODO Use weak references in this map to prevent memory leaks
  26. private static ConcurrentHashMap<Class<?>, ClassXMLInfo> FIELD_MAP = new ConcurrentHashMap<Class<?>, ClassXMLInfo>();
  27. @SuppressWarnings("unchecked")
  28. public static Element toXML(Object bean, Document doc){
  29. ClassXMLInfo classInfo = FIELD_MAP.get(bean.getClass());
  30. if(classInfo == null){
  31. Class<?> clazz = bean.getClass();
  32. XMLElement xmlElement = clazz.getAnnotation(XMLElement.class);
  33. if(xmlElement == null){
  34. throw new MissingXMLAnnotationException(clazz);
  35. }
  36. String elementName = xmlElement.name();
  37. if(StringUtils.isEmpty(elementName)){
  38. elementName = clazz.getSimpleName();
  39. }
  40. List<FieldXMLInfo> annotatedFields = new ArrayList<FieldXMLInfo>();
  41. Class<?> currentClazz = clazz;
  42. while (currentClazz != Object.class) {
  43. Field[] fields = currentClazz.getDeclaredFields();
  44. for(Field field : fields){
  45. XMLElement elementAnnotation = field.getAnnotation(XMLElement.class);
  46. if(elementAnnotation != null){
  47. String name = elementAnnotation.name();
  48. if(StringUtils.isEmpty(name)){
  49. name = field.getName();
  50. }
  51. Stringyfier valueFormatter = null;
  52. if(elementAnnotation.valueFormatter() != DummyStringyfier.class){
  53. try {
  54. valueFormatter = elementAnnotation.valueFormatter().newInstance();
  55. } catch (InstantiationException e) {
  56. throw new RuntimeException(e);
  57. } catch (IllegalAccessException e) {
  58. throw new RuntimeException(e);
  59. }
  60. }
  61. if(Collection.class.isAssignableFrom(field.getType())){
  62. boolean elementable = false;
  63. if(ReflectionUtils.isGenericlyTyped(field) && Elementable.class.isAssignableFrom((Class<?>) ReflectionUtils.getGenericType(field))){
  64. elementable = true;
  65. }
  66. String childName = elementAnnotation.childName();
  67. if(StringUtils.isEmpty(childName)){
  68. childName = "value";
  69. }
  70. annotatedFields.add(new FieldXMLInfo(name, field, FieldType.Element,elementAnnotation.cdata(),elementable,true,false,childName,elementAnnotation.skipChildParentElement(),valueFormatter));
  71. }else if(field.getType().isArray()){
  72. boolean elementable = false;
  73. if(Elementable.class.isAssignableFrom(field.getType())){
  74. elementable = true;
  75. }
  76. String childName = elementAnnotation.childName();
  77. if(StringUtils.isEmpty(childName)){
  78. childName = "value";
  79. }
  80. annotatedFields.add(new FieldXMLInfo(name, field, FieldType.Element,elementAnnotation.cdata(),elementable,false,true,childName,elementAnnotation.skipChildParentElement(),valueFormatter));
  81. }else{
  82. String childName = null;
  83. if(!StringUtils.isEmpty(elementAnnotation.childName())){
  84. childName = elementAnnotation.childName();
  85. }
  86. annotatedFields.add(new FieldXMLInfo(name, field, FieldType.Element,elementAnnotation.cdata(),Elementable.class.isAssignableFrom(field.getType()),false,false,childName,false,valueFormatter));
  87. }
  88. ReflectionUtils.fixFieldAccess(field);
  89. }
  90. XMLAttribute attributeAnnotation = field.getAnnotation(XMLAttribute.class);
  91. if(attributeAnnotation != null){
  92. String name = attributeAnnotation.name();
  93. if(StringUtils.isEmpty(name)){
  94. name = field.getName();
  95. }
  96. Stringyfier valueFormatter = null;
  97. if(attributeAnnotation.valueFormatter() != DummyStringyfier.class){
  98. try {
  99. valueFormatter = attributeAnnotation.valueFormatter().newInstance();
  100. } catch (InstantiationException e) {
  101. throw new RuntimeException(e);
  102. } catch (IllegalAccessException e) {
  103. throw new RuntimeException(e);
  104. }
  105. }
  106. annotatedFields.add(new FieldXMLInfo(name, field, FieldType.Attribute,false,false,false,false,null,false,valueFormatter));
  107. ReflectionUtils.fixFieldAccess(field);
  108. }
  109. }
  110. currentClazz = currentClazz.getSuperclass();
  111. }
  112. if(annotatedFields.isEmpty()){
  113. throw new NoAnnotatedFieldsFoundException(clazz,XMLElement.class,XMLAttribute.class);
  114. }
  115. classInfo = new ClassXMLInfo(elementName, annotatedFields);
  116. FIELD_MAP.put(clazz, classInfo);
  117. }
  118. Element classElement = doc.createElement(classInfo.getElementName());
  119. for(FieldXMLInfo fieldInfo : classInfo.getFields()){
  120. Object fieldValue;
  121. try {
  122. fieldValue = fieldInfo.getField().get(bean);
  123. } catch (IllegalArgumentException e) {
  124. throw new RuntimeException(e);
  125. } catch (IllegalAccessException e) {
  126. throw new RuntimeException(e);
  127. }
  128. if(fieldValue == null){
  129. continue;
  130. }else if(!fieldInfo.isList() && fieldInfo.getValueFormatter() != null){
  131. fieldValue = fieldInfo.getValueFormatter().format(fieldValue);
  132. }else if(fieldValue instanceof Date){
  133. fieldValue = DateUtils.DATE_TIME_FORMATTER.format(fieldValue);
  134. }
  135. if(fieldInfo.getFieldType() == FieldType.Attribute){
  136. classElement.setAttribute(fieldInfo.getName(), fieldValue.toString());
  137. }else if(fieldInfo.isList()){
  138. List<?> fieldValues = (List<?>)fieldValue;
  139. if(fieldValues.isEmpty()){
  140. continue;
  141. }
  142. Element subElement;
  143. if(fieldInfo.skipSubElement()){
  144. subElement = classElement;
  145. }else{
  146. subElement = doc.createElement(fieldInfo.getName());
  147. }
  148. for(Object value : fieldValues){
  149. if(value != null){
  150. parseValue(fieldInfo,value,subElement,doc);
  151. }
  152. }
  153. if(!fieldInfo.skipSubElement() && subElement.hasChildNodes()){
  154. classElement.appendChild(subElement);
  155. }
  156. }else if(fieldInfo.isArray()){
  157. Object[] fieldValues = (Object[])fieldValue;
  158. if(ArrayUtils.isEmpty(fieldValues)){
  159. continue;
  160. }
  161. Element subElement;
  162. if(fieldInfo.skipSubElement()){
  163. subElement = classElement;
  164. }else{
  165. subElement = doc.createElement(fieldInfo.getName());
  166. }
  167. for(Object value : fieldValues){
  168. if(value != null){
  169. parseValue(fieldInfo,value,subElement,doc);
  170. }
  171. }
  172. if(!fieldInfo.skipSubElement() && subElement.hasChildNodes()){
  173. classElement.appendChild(subElement);
  174. }
  175. }else if(fieldInfo.isElementable()){
  176. Element subElement = ((Elementable)fieldValue).toXML(doc);
  177. if(subElement != null){
  178. if(fieldInfo.getChildName() != null){
  179. Element middleElement = doc.createElement(fieldInfo.getChildName());
  180. classElement.appendChild(middleElement);
  181. middleElement.appendChild(subElement);
  182. }else{
  183. classElement.appendChild(subElement);
  184. }
  185. }
  186. }else if(fieldInfo.isCDATA()){
  187. classElement.appendChild(XMLUtils.createCDATAElement(fieldInfo.getName(), fieldValue.toString(), doc));
  188. }else{
  189. classElement.appendChild(XMLUtils.createElement(fieldInfo.getName(), fieldValue.toString(), doc));
  190. }
  191. }
  192. return classElement;
  193. }
  194. private static void parseValue(FieldXMLInfo fieldInfo, Object value, Element subElement, Document doc) {
  195. if(fieldInfo.getValueFormatter() != null){
  196. value = fieldInfo.getValueFormatter().format(value);
  197. }else if(value instanceof Date){
  198. value = DateUtils.DATE_TIME_FORMATTER.format(value);
  199. }
  200. if(fieldInfo.isElementable()){
  201. Element subSubElement = ((Elementable)value).toXML(doc);
  202. if(subSubElement != null){
  203. subElement.appendChild(subSubElement);
  204. }
  205. }else{
  206. if(fieldInfo.isCDATA()){
  207. subElement.appendChild(XMLUtils.createCDATAElement(fieldInfo.getChildName(), value, doc));
  208. }else{
  209. subElement.appendChild(XMLUtils.createElement(fieldInfo.getChildName(), value, doc));
  210. }
  211. }
  212. }
  213. }