Mercurial > hg > Members > sugi > MessagePack-java
comparison src/main/java/org/msgpack/template/builder/AbstractTemplateBuilder.java @ 0:cb825acd883a
first commit
author | sugi |
---|---|
date | Sat, 18 Oct 2014 15:06:15 +0900 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:cb825acd883a |
---|---|
1 // | |
2 // MessagePack for Java | |
3 // | |
4 // Copyright (C) 2009 - 2013 FURUHASHI Sadayuki | |
5 // | |
6 // Licensed under the Apache License, Version 2.0 (the "License"); | |
7 // you may not use this file except in compliance with the License. | |
8 // You may obtain a copy of the License at | |
9 // | |
10 // http://www.apache.org/licenses/LICENSE-2.0 | |
11 // | |
12 // Unless required by applicable law or agreed to in writing, software | |
13 // distributed under the License is distributed on an "AS IS" BASIS, | |
14 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
15 // See the License for the specific language governing permissions and | |
16 // limitations under the License. | |
17 // | |
18 package org.msgpack.template.builder; | |
19 | |
20 import java.lang.annotation.Annotation; | |
21 import java.lang.reflect.AccessibleObject; | |
22 import java.lang.reflect.Field; | |
23 import java.lang.reflect.GenericArrayType; | |
24 import java.lang.reflect.Modifier; | |
25 import java.lang.reflect.Type; | |
26 import java.util.ArrayList; | |
27 import java.util.List; | |
28 | |
29 import org.msgpack.annotation.Beans; | |
30 import org.msgpack.annotation.Ignore; | |
31 import org.msgpack.annotation.Index; | |
32 import org.msgpack.annotation.Message; | |
33 import org.msgpack.annotation.MessagePackBeans; | |
34 import org.msgpack.annotation.MessagePackMessage; | |
35 import org.msgpack.annotation.MessagePackOrdinalEnum; | |
36 import org.msgpack.annotation.NotNullable; | |
37 import org.msgpack.annotation.Optional; | |
38 import org.msgpack.annotation.OrdinalEnum; | |
39 import org.msgpack.template.FieldList; | |
40 import org.msgpack.template.FieldOption; | |
41 import org.msgpack.template.Template; | |
42 import org.msgpack.template.TemplateRegistry; | |
43 import org.msgpack.template.builder.TemplateBuildException; | |
44 | |
45 public abstract class AbstractTemplateBuilder implements TemplateBuilder { | |
46 | |
47 protected TemplateRegistry registry; | |
48 | |
49 protected AbstractTemplateBuilder(TemplateRegistry registry) { | |
50 this.registry = registry; | |
51 } | |
52 | |
53 @Override | |
54 public <T> Template<T> buildTemplate(final Type targetType) | |
55 throws TemplateBuildException { | |
56 @SuppressWarnings("unchecked") | |
57 Class<T> targetClass = (Class<T>) targetType; | |
58 checkClassValidation(targetClass); | |
59 FieldOption fieldOption = getFieldOption(targetClass); | |
60 FieldEntry[] entries = toFieldEntries(targetClass, fieldOption); | |
61 return buildTemplate(targetClass, entries); | |
62 } | |
63 | |
64 @Override | |
65 public <T> Template<T> buildTemplate(final Class<T> targetClass, final FieldList fieldList) | |
66 throws TemplateBuildException { | |
67 checkClassValidation(targetClass); | |
68 FieldEntry[] entries = toFieldEntries(targetClass, fieldList); | |
69 return buildTemplate(targetClass, entries); | |
70 } | |
71 | |
72 protected abstract <T> Template<T> buildTemplate(Class<T> targetClass, FieldEntry[] entries); | |
73 | |
74 protected void checkClassValidation(final Class<?> targetClass) { | |
75 if (targetClass.isInterface()) { | |
76 throw new TemplateBuildException( | |
77 "Cannot build template for interface: " + targetClass.getName()); | |
78 } | |
79 if (Modifier.isAbstract(targetClass.getModifiers())) { | |
80 throw new TemplateBuildException( | |
81 "Cannot build template for abstract class: " + targetClass.getName()); | |
82 } | |
83 if (targetClass.isArray()) { | |
84 throw new TemplateBuildException( | |
85 "Cannot build template for array class: " + targetClass.getName()); | |
86 } | |
87 if (targetClass.isPrimitive()) { | |
88 throw new TemplateBuildException( | |
89 "Cannot build template of primitive type: " + targetClass.getName()); | |
90 } | |
91 } | |
92 | |
93 protected FieldOption getFieldOption(Class<?> targetClass) { | |
94 Message m = targetClass.getAnnotation(Message.class); | |
95 if (m == null) { | |
96 return FieldOption.DEFAULT; | |
97 } | |
98 MessagePackMessage mpm = targetClass | |
99 .getAnnotation(MessagePackMessage.class); | |
100 if (mpm == null) { | |
101 return FieldOption.DEFAULT; | |
102 } | |
103 // TODO #MN | |
104 return m.value(); | |
105 } | |
106 | |
107 private FieldEntry[] toFieldEntries(final Class<?> targetClass, final FieldList flist) { | |
108 List<FieldList.Entry> src = flist.getList(); | |
109 FieldEntry[] entries = new FieldEntry[src.size()]; | |
110 for (int i = 0; i < src.size(); i++) { | |
111 FieldList.Entry s = src.get(i); | |
112 if (s.isAvailable()) { | |
113 try { | |
114 entries[i] = new DefaultFieldEntry(targetClass.getDeclaredField(s.getName()), s.getOption()); | |
115 } catch (SecurityException e) { | |
116 throw new TemplateBuildException(e); | |
117 } catch (NoSuchFieldException e) { | |
118 throw new TemplateBuildException(e); | |
119 } | |
120 } else { | |
121 entries[i] = new DefaultFieldEntry(); | |
122 } | |
123 } | |
124 return entries; | |
125 } | |
126 | |
127 protected FieldEntry[] toFieldEntries(final Class<?> targetClass, final FieldOption from) { | |
128 Field[] fields = getFields(targetClass); | |
129 | |
130 /* | |
131 * index: | |
132 * | |
133 * @Index(0) | |
134 * int field_a; // 0 | |
135 * int field_b; // 1 | |
136 * @Index(3) | |
137 * int field_c; // 3 | |
138 * int field_d; // 4 | |
139 * @Index(2) | |
140 * int field_e; // 2 | |
141 * int field_f; // 5 | |
142 */ | |
143 List<FieldEntry> indexed = new ArrayList<FieldEntry>(); | |
144 int maxIndex = -1; | |
145 for (Field f : fields) { | |
146 FieldOption opt = getFieldOption(f, from); | |
147 if (opt == FieldOption.IGNORE) { | |
148 // skip | |
149 continue; | |
150 } | |
151 | |
152 int index = getFieldIndex(f, maxIndex); | |
153 if (indexed.size() > index && indexed.get(index) != null) { | |
154 throw new TemplateBuildException("duplicated index: " + index); | |
155 } | |
156 if (index < 0) { | |
157 throw new TemplateBuildException("invalid index: " + index); | |
158 } | |
159 | |
160 while (indexed.size() <= index) { | |
161 indexed.add(null); | |
162 } | |
163 indexed.set(index, new DefaultFieldEntry(f, opt)); | |
164 | |
165 if (maxIndex < index) { | |
166 maxIndex = index; | |
167 } | |
168 } | |
169 | |
170 FieldEntry[] entries = new FieldEntry[maxIndex + 1]; | |
171 for (int i = 0; i < indexed.size(); i++) { | |
172 FieldEntry e = indexed.get(i); | |
173 if (e == null) { | |
174 entries[i] = new DefaultFieldEntry(); | |
175 } else { | |
176 entries[i] = e; | |
177 } | |
178 } | |
179 return entries; | |
180 } | |
181 | |
182 private Field[] getFields(Class<?> targetClass) { | |
183 // order: [fields of super class, ..., fields of this class] | |
184 List<Field[]> succ = new ArrayList<Field[]>(); | |
185 int total = 0; | |
186 for (Class<?> c = targetClass; c != Object.class; c = c.getSuperclass()) { | |
187 Field[] fields = c.getDeclaredFields(); | |
188 total += fields.length; | |
189 succ.add(fields); | |
190 } | |
191 Field[] result = new Field[total]; | |
192 int off = 0; | |
193 for (int i = succ.size() - 1; i >= 0; i--) { | |
194 Field[] fields = succ.get(i); | |
195 System.arraycopy(fields, 0, result, off, fields.length); | |
196 off += fields.length; | |
197 } | |
198 return result; | |
199 } | |
200 | |
201 private FieldOption getFieldOption(Field field, FieldOption from) { | |
202 int mod = field.getModifiers(); | |
203 // default mode: | |
204 // transient, static, final : Ignore | |
205 // primitive type : NotNullable | |
206 // reference type : Ignore | |
207 if (Modifier.isStatic(mod) || Modifier.isFinal(mod) | |
208 || Modifier.isTransient(mod)) { | |
209 return FieldOption.IGNORE; | |
210 } | |
211 | |
212 if (isAnnotated(field, Ignore.class)) { | |
213 return FieldOption.IGNORE; | |
214 } else if (isAnnotated(field, Optional.class)) { | |
215 return FieldOption.OPTIONAL; | |
216 } else if (isAnnotated(field, NotNullable.class)) { | |
217 return FieldOption.NOTNULLABLE; | |
218 } | |
219 | |
220 if (from != FieldOption.DEFAULT) { | |
221 return from; | |
222 } | |
223 | |
224 if (field.getType().isPrimitive()) { | |
225 return FieldOption.NOTNULLABLE; | |
226 } else { | |
227 return FieldOption.OPTIONAL; | |
228 } | |
229 } | |
230 | |
231 private int getFieldIndex(final Field field, int maxIndex) { | |
232 Index a = field.getAnnotation(Index.class); | |
233 if (a == null) { | |
234 return maxIndex + 1; | |
235 } else { | |
236 return a.value(); | |
237 } | |
238 } | |
239 | |
240 @Override | |
241 public void writeTemplate(Type targetType, String directoryName) { | |
242 throw new UnsupportedOperationException(targetType.toString()); | |
243 } | |
244 | |
245 @Override | |
246 public <T> Template<T> loadTemplate(Type targetType) { | |
247 return null; | |
248 } | |
249 | |
250 public static boolean isAnnotated(Class<?> targetClass, | |
251 Class<? extends Annotation> with) { | |
252 return targetClass.getAnnotation(with) != null; | |
253 } | |
254 | |
255 public static boolean isAnnotated(AccessibleObject accessibleObject, Class<? extends Annotation> with) { | |
256 return accessibleObject.getAnnotation(with) != null; | |
257 } | |
258 | |
259 public static boolean matchAtClassTemplateBuilder(Class<?> targetClass, boolean hasAnnotation) { | |
260 if (hasAnnotation) { | |
261 return AbstractTemplateBuilder.isAnnotated(targetClass, Message.class) | |
262 || AbstractTemplateBuilder.isAnnotated(targetClass, MessagePackMessage.class); | |
263 } else { | |
264 return !targetClass.isEnum() && !targetClass.isInterface(); | |
265 } | |
266 } | |
267 | |
268 public static boolean matchAtBeansClassTemplateBuilder(Type targetType, boolean hasAnnotation) { | |
269 Class<?> targetClass = (Class<?>) targetType; | |
270 if (hasAnnotation) { | |
271 return AbstractTemplateBuilder.isAnnotated((Class<?>) targetType, Beans.class) | |
272 || AbstractTemplateBuilder.isAnnotated((Class<?>) targetType, MessagePackBeans.class); | |
273 } else { | |
274 return !targetClass.isEnum() || !targetClass.isInterface(); | |
275 } | |
276 } | |
277 | |
278 public static boolean matchAtArrayTemplateBuilder(Class<?> targetClass, boolean hasAnnotation) { | |
279 if (((Type) targetClass) instanceof GenericArrayType) { | |
280 return true; | |
281 } | |
282 return targetClass.isArray(); | |
283 } | |
284 | |
285 public static boolean matchAtOrdinalEnumTemplateBuilder(Class<?> targetClass, boolean hasAnnotation) { | |
286 if (hasAnnotation) { | |
287 return AbstractTemplateBuilder.isAnnotated(targetClass, OrdinalEnum.class) | |
288 || AbstractTemplateBuilder.isAnnotated(targetClass, MessagePackOrdinalEnum.class); | |
289 } else { | |
290 return targetClass.isEnum(); | |
291 } | |
292 } | |
293 } |