View Javadoc
1   package com.foxinmy.weixin4j.xml;
2   
3   import java.io.StringReader;
4   import java.io.StringWriter;
5   import java.lang.reflect.Field;
6   import java.lang.reflect.ParameterizedType;
7   import java.lang.reflect.Type;
8   import java.util.ArrayList;
9   import java.util.HashMap;
10  import java.util.List;
11  import java.util.Map;
12  import java.util.Map.Entry;
13  import java.util.Set;
14  import java.util.regex.Matcher;
15  import java.util.regex.Pattern;
16  
17  import javax.xml.bind.JAXBContext;
18  import javax.xml.bind.JAXBException;
19  import javax.xml.bind.Unmarshaller;
20  import javax.xml.bind.annotation.XmlRootElement;
21  import javax.xml.stream.XMLInputFactory;
22  import javax.xml.stream.XMLOutputFactory;
23  import javax.xml.stream.XMLStreamConstants;
24  import javax.xml.stream.XMLStreamException;
25  import javax.xml.stream.XMLStreamReader;
26  import javax.xml.stream.XMLStreamWriter;
27  import javax.xml.transform.stream.StreamSource;
28  
29  import com.foxinmy.weixin4j.util.Consts;
30  import com.foxinmy.weixin4j.util.ReflectionUtil;
31  import com.foxinmy.weixin4j.util.StringUtil;
32  
33  /**
34   * 对 后缀为_$n 的 xml节点反序列化
35   * 
36   * @className ListsuffixResultDeserializer
37   * @author jinyu(foxinmy@gmail.com)
38   * @date 2015年3月24日
39   * @since JDK 1.6
40   * @see
41   */
42  public class ListsuffixResultDeserializer {
43  
44  	private static Pattern DEFAULT_PATTERN;
45  	static {
46  		String regex = null;
47  		try {
48  			Object value = ListsuffixResult.class.getMethod("value")
49  					.getDefaultValue();
50  			if (value instanceof String) {
51  				regex = (String) value;
52  			} else if (value instanceof String[]) {
53  				regex = ((String[]) value)[0];
54  			}
55  		} catch (NoSuchMethodException e) {
56  			;
57  		}
58  		if (StringUtil.isBlank(regex)) {
59  			regex = "(_\\d)$";
60  		}
61  		DEFAULT_PATTERN = Pattern.compile(regex);
62  	}
63  
64  	/**
65  	 * 对包含$n节点的xml反序列化
66  	 * 
67  	 * @param content
68  	 *            xml内容
69  	 * @param clazz
70  	 * @return
71  	 */
72  	public static <T> T deserialize(String content, Class<T> clazz) {
73  		T t = XmlStream.fromXML(content, clazz);
74  		Map<Field, String[]> listsuffixFields = getListsuffixFields(clazz);
75  		if (!listsuffixFields.isEmpty()) {
76  			for (Entry<Field, String[]> entry : listsuffixFields.entrySet()) {
77  				Field field = entry.getKey();
78  				Type type = field.getGenericType();
79  				Class<?> wrapperClazz = null;
80  				if (type instanceof ParameterizedType) {
81  					wrapperClazz = (Class<?>) ((ParameterizedType) type)
82  							.getActualTypeArguments()[0];
83  				} else {
84  					continue;
85  				}
86  				ListWrapper<?> listWrapper = deserializeToListWrapper(content,
87  						wrapperClazz, entry.getValue());
88  				if (listWrapper != null) {
89  					try {
90  						field.setAccessible(true);
91  						field.set(t, listWrapper.getItems());
92  					} catch (Exception e) {
93  						;
94  					}
95  				}
96  			}
97  		}
98  		return t;
99  	}
100 
101 	@SuppressWarnings("unchecked")
102 	public static <T> ListWrapper<T> deserializeToListWrapper(String content,
103 			Class<T> clazz, String... matchPattern) {
104 		XMLStreamReader xr = null;
105 		XMLStreamWriter xw = null;
106 		try {
107 			xr = XMLInputFactory.newInstance().createXMLStreamReader(
108 					new StringReader(content));
109 			List<Pattern> patterns = new ArrayList<Pattern>();
110 			for (String pattern : matchPattern) {
111 				patterns.add(Pattern.compile(pattern));
112 			}
113 			Matcher matcher = null;
114 			Map<String, Map<String, String>> outMap = new HashMap<String, Map<String, String>>();
115 			while (true) {
116 				int event = xr.next();
117 				if (event == XMLStreamConstants.END_DOCUMENT) {
118 					break;
119 				} else if (event == XMLStreamConstants.START_ELEMENT) {
120 					String name = xr.getLocalName();
121 					for (Pattern pattern : patterns) {
122 						if ((matcher = pattern.matcher(name)).find()) {
123 							while (true) {
124 								event = xr.next();
125 								if (event == XMLStreamConstants.START_ELEMENT) {
126 									name = xr.getLocalName();
127 								} else if (event == XMLStreamConstants.END_ELEMENT) {
128 									break;
129 								} else if (event == XMLStreamConstants.CHARACTERS  || event == XMLStreamConstants.CDATA) {
130 									String key = matcher.group();
131 									if (!pattern.pattern().equals(
132 											DEFAULT_PATTERN.pattern())) {
133 										matcher = DEFAULT_PATTERN.matcher(name);
134 										matcher.find();
135 										key = matcher.group();
136 									}
137 									Map<String, String> innerMap = null;
138 									if ((innerMap = outMap.get(key)) == null) {
139 										innerMap = new HashMap<String, String>();
140 										outMap.put(key, innerMap);
141 									}
142 									innerMap.put(name.replace(key, ""),
143 											xr.getText());
144 								}
145 							}
146 							break;
147 						}
148 					}
149 				}
150 			}
151 			if (!outMap.isEmpty()) {
152 				StringWriter sw = new StringWriter();
153 				xw = XMLOutputFactory.newInstance().createXMLStreamWriter(sw);
154 				xw.writeStartDocument(Consts.UTF_8.name(), "1.0");
155 				xw.writeStartElement(clazz.getCanonicalName());
156 				String itemName = StringUtil
157 						.uncapitalize(clazz.getSimpleName());
158 				XmlRootElement rootElement = clazz
159 						.getAnnotation(XmlRootElement.class);
160 				if (rootElement != null
161 						&& StringUtil.isNotBlank(rootElement.name())) {
162 					try {
163 						if (!rootElement.name().equals(
164 								XmlRootElement.class.getMethod("name")
165 										.getDefaultValue().toString())) {
166 							itemName = rootElement.name();
167 						}
168 					} catch (NoSuchMethodException e) {
169 						;
170 					}
171 				}
172 				for (Entry<String, Map<String, String>> outE : outMap
173 						.entrySet()) {
174 					xw.writeStartElement(itemName);
175 					for (Entry<String, String> innerE : outE
176 							.getValue().entrySet()) {
177 						xw.writeStartElement(innerE.getKey());
178 						xw.writeCharacters(innerE.getValue());
179 						xw.writeEndElement();
180 					}
181 					xw.writeEndElement();
182 				}
183 				xw.writeEndElement();
184 				xw.writeEndDocument();
185 				JAXBContext ctx = JAXBContext.newInstance(ListWrapper.class,
186 						clazz);
187 				Unmarshaller u = ctx.createUnmarshaller();
188 				return u.unmarshal(
189 						new StreamSource(new StringReader(sw.getBuffer()
190 								.toString())), ListWrapper.class).getValue();
191 			}
192 			return null;
193 		} catch (XMLStreamException e) {
194 			throw new IllegalArgumentException(e);
195 		} catch (JAXBException e) {
196 			throw new RuntimeException(e);
197 		} finally {
198 			try {
199 				if (xw != null) {
200 					xw.close();
201 				}
202 				if (xr != null) {
203 					xr.close();
204 				}
205 			} catch (XMLStreamException e) {
206 				;
207 			}
208 		}
209 	}
210 
211 	public static Map<Field, String[]> getListsuffixFields(Class<?> clazz) {
212 		Map<Field, String[]> listsuffixFields = new HashMap<Field, String[]>();
213 		Set<Field> allFields = ReflectionUtil.getAllField(clazz);
214 		ListsuffixResult listsuffixResult = null;
215 		for (Field field : allFields) {
216 			listsuffixResult = field.getAnnotation(ListsuffixResult.class);
217 			if (listsuffixResult != null) {
218 				listsuffixFields.put(field, listsuffixResult.value());
219 			}
220 		}
221 		return listsuffixFields;
222 	}
223 }