comparison src/main/java/org/msgpack/template/TemplateRegistry.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;
19
20 import java.util.Collection;
21 import java.util.Collections;
22 import java.util.Date;
23 import java.util.List;
24 import java.util.Map;
25 import java.util.HashMap;
26 import java.util.Set;
27 import java.lang.reflect.GenericArrayType;
28 import java.lang.reflect.ParameterizedType;
29 import java.lang.reflect.Type;
30 import java.lang.reflect.TypeVariable;
31 import java.lang.reflect.WildcardType;
32 import java.math.BigDecimal;
33 import java.math.BigInteger;
34 import java.nio.ByteBuffer;
35
36 import org.msgpack.MessagePackable;
37 import org.msgpack.MessageTypeException;
38 import org.msgpack.template.BigIntegerTemplate;
39 import org.msgpack.template.BooleanTemplate;
40 import org.msgpack.template.ByteArrayTemplate;
41 import org.msgpack.template.ByteTemplate;
42 import org.msgpack.template.DoubleArrayTemplate;
43 import org.msgpack.template.DoubleTemplate;
44 import org.msgpack.template.FieldList;
45 import org.msgpack.template.FloatArrayTemplate;
46 import org.msgpack.template.FloatTemplate;
47 import org.msgpack.template.GenericTemplate;
48 import org.msgpack.template.IntegerArrayTemplate;
49 import org.msgpack.template.IntegerTemplate;
50 import org.msgpack.template.LongArrayTemplate;
51 import org.msgpack.template.LongTemplate;
52 import org.msgpack.template.ShortArrayTemplate;
53 import org.msgpack.template.ShortTemplate;
54 import org.msgpack.template.StringTemplate;
55 import org.msgpack.template.Template;
56 import org.msgpack.template.ValueTemplate;
57 import org.msgpack.template.builder.ArrayTemplateBuilder;
58 import org.msgpack.template.builder.TemplateBuilder;
59 import org.msgpack.template.builder.TemplateBuilderChain;
60 import org.msgpack.type.Value;
61
62 @SuppressWarnings({ "rawtypes", "unchecked" })
63 public class TemplateRegistry {
64
65 private TemplateRegistry parent = null;
66
67 private TemplateBuilderChain chain;
68
69 Map<Type, Template<Type>> cache;
70
71 private Map<Type, GenericTemplate> genericCache;
72
73 /**
74 * create <code>TemplateRegistry</code> object of root.
75 */
76 private TemplateRegistry() {
77 parent = null;
78 chain = createTemplateBuilderChain();
79 genericCache = new HashMap<Type, GenericTemplate>();
80 cache = new HashMap<Type, Template<Type>>();
81 registerTemplates();
82 cache = Collections.unmodifiableMap(cache);
83 }
84
85 /**
86 *
87 * @param registry
88 */
89 public TemplateRegistry(TemplateRegistry registry) {
90 if (registry != null) {
91 parent = registry;
92 } else {
93 parent = new TemplateRegistry();
94 }
95 chain = createTemplateBuilderChain();
96 cache = new HashMap<Type, Template<Type>>();
97 genericCache = new HashMap<Type, GenericTemplate>();
98 registerTemplatesWhichRefersRegistry();
99 }
100
101 protected TemplateBuilderChain createTemplateBuilderChain() {
102 return new TemplateBuilderChain(this);
103 }
104
105 public void setClassLoader(final ClassLoader cl) {
106 chain = new TemplateBuilderChain(this, cl);
107 }
108
109 private void registerTemplates() {
110 register(boolean.class, BooleanTemplate.getInstance());
111 register(Boolean.class, BooleanTemplate.getInstance());
112 register(byte.class, ByteTemplate.getInstance());
113 register(Byte.class, ByteTemplate.getInstance());
114 register(short.class, ShortTemplate.getInstance());
115 register(Short.class, ShortTemplate.getInstance());
116 register(int.class, IntegerTemplate.getInstance());
117 register(Integer.class, IntegerTemplate.getInstance());
118 register(long.class, LongTemplate.getInstance());
119 register(Long.class, LongTemplate.getInstance());
120 register(float.class, FloatTemplate.getInstance());
121 register(Float.class, FloatTemplate.getInstance());
122 register(double.class, DoubleTemplate.getInstance());
123 register(Double.class, DoubleTemplate.getInstance());
124 register(BigInteger.class, BigIntegerTemplate.getInstance());
125 register(char.class, CharacterTemplate.getInstance());
126 register(Character.class, CharacterTemplate.getInstance());
127 register(boolean[].class, BooleanArrayTemplate.getInstance());
128 register(short[].class, ShortArrayTemplate.getInstance());
129 register(int[].class, IntegerArrayTemplate.getInstance());
130 register(long[].class, LongArrayTemplate.getInstance());
131 register(float[].class, FloatArrayTemplate.getInstance());
132 register(double[].class, DoubleArrayTemplate.getInstance());
133 register(String.class, StringTemplate.getInstance());
134 register(byte[].class, ByteArrayTemplate.getInstance());
135 register(ByteBuffer.class, ByteBufferTemplate.getInstance());
136 register(Value.class, ValueTemplate.getInstance());
137 register(BigDecimal.class, BigDecimalTemplate.getInstance());
138 register(Date.class, DateTemplate.getInstance());
139
140 registerTemplatesWhichRefersRegistry();
141
142 }
143
144 protected void registerTemplatesWhichRefersRegistry() {
145 AnyTemplate anyTemplate = new AnyTemplate(this);
146
147 register(List.class, new ListTemplate(anyTemplate));
148 register(Set.class, new SetTemplate(anyTemplate));
149 register(Collection.class, new CollectionTemplate(anyTemplate));
150 register(Map.class, new MapTemplate(anyTemplate, anyTemplate));
151 registerGeneric(List.class, new GenericCollectionTemplate(this, ListTemplate.class));
152 registerGeneric(Set.class, new GenericCollectionTemplate(this, SetTemplate.class));
153 registerGeneric(Collection.class, new GenericCollectionTemplate(this, CollectionTemplate.class));
154 registerGeneric(Map.class, new GenericMapTemplate(this, MapTemplate.class));
155 }
156
157 public void register(final Class<?> targetClass) {
158 buildAndRegister(null, targetClass, false, null);
159 }
160
161 public void register(final Class<?> targetClass, final FieldList flist) {
162 if (flist == null) {
163 throw new NullPointerException("FieldList object is null");
164 }
165
166 buildAndRegister(null, targetClass, false, flist);
167 }
168
169 public synchronized void register(final Type targetType, final Template tmpl) {
170 if (tmpl == null) {
171 throw new NullPointerException("Template object is null");
172 }
173
174 if (targetType instanceof ParameterizedType) {
175 cache.put(((ParameterizedType) targetType).getRawType(), tmpl);
176 } else {
177 cache.put(targetType, tmpl);
178 }
179 }
180
181 public synchronized void registerGeneric(final Type targetType, final GenericTemplate tmpl) {
182 if (targetType instanceof ParameterizedType) {
183 genericCache.put(((ParameterizedType) targetType).getRawType(),
184 tmpl);
185 } else {
186 genericCache.put(targetType, tmpl);
187 }
188 }
189
190 public synchronized boolean unregister(final Type targetType) {
191 Template<Type> tmpl = cache.remove(targetType);
192 return tmpl != null;
193 }
194
195 public synchronized void unregister() {
196 cache.clear();
197 }
198
199 public synchronized Template lookup(Type targetType) {
200 Template tmpl;
201
202 if (targetType instanceof ParameterizedType) {
203 // ParameterizedType is not a Class<?>
204 ParameterizedType paramedType = (ParameterizedType) targetType;
205 tmpl = lookupGenericType(paramedType);
206 if (tmpl != null) {
207 return tmpl;
208 }
209 targetType = paramedType.getRawType();
210 }
211
212 tmpl = lookupGenericArrayType(targetType);
213 if (tmpl != null) {
214 return tmpl;
215 }
216
217 tmpl = lookupCache(targetType);
218 if (tmpl != null) {
219 return tmpl;
220 }
221
222 if (targetType instanceof WildcardType ||
223 targetType instanceof TypeVariable) {
224 // WildcardType is not a Class<?>
225 tmpl = new AnyTemplate<Object>(this);
226 register(targetType, tmpl);
227 return tmpl;
228 }
229
230 Class<?> targetClass = (Class<?>) targetType;
231
232 // MessagePackable interface is implemented
233 if (MessagePackable.class.isAssignableFrom(targetClass)) {
234 // FIXME #MN
235 // following processing should be merged into lookAfterBuilding
236 // or lookupInterfaceTypes method in next version
237 tmpl = new MessagePackableTemplate(targetClass);
238 register(targetClass, tmpl);
239 return tmpl;
240 }
241
242 if (targetClass.isInterface()) {
243 // writing interfaces will succeed
244 // reading into interfaces will fail
245 tmpl = new AnyTemplate<Object>(this);
246 register(targetType, tmpl);
247 return tmpl;
248 }
249
250 // find matched template builder and build template
251 tmpl = lookupAfterBuilding(targetClass);
252 if (tmpl != null) {
253 return tmpl;
254 }
255
256 // lookup template of interface type
257 tmpl = lookupInterfaceTypes(targetClass);
258 if (tmpl != null) {
259 return tmpl;
260 }
261
262 // lookup template of superclass type
263 tmpl = lookupSuperclasses(targetClass);
264 if (tmpl != null) {
265 return tmpl;
266 }
267
268 // lookup template of interface type of superclasss
269 tmpl = lookupSuperclassInterfaceTypes(targetClass);
270 if (tmpl != null) {
271 return tmpl;
272 }
273
274 throw new MessageTypeException(
275 "Cannot find template for " + targetClass + " class. " +
276 "Try to add @Message annotation to the class or call MessagePack.register(Type).");
277 }
278
279 private Template<Type> lookupGenericType(ParameterizedType paramedType) {
280 Template<Type> tmpl = lookupGenericTypeImpl(paramedType);
281 if (tmpl != null) {
282 return tmpl;
283 }
284
285 try {
286 tmpl = parent.lookupGenericTypeImpl(paramedType);
287 if (tmpl != null) {
288 return tmpl;
289 }
290 } catch (NullPointerException e) { // ignore
291 }
292
293 tmpl = lookupGenericInterfaceTypes(paramedType);
294 if (tmpl != null) {
295 return tmpl;
296 }
297
298 tmpl = lookupGenericSuperclasses(paramedType);
299 if (tmpl != null) {
300 return tmpl;
301 }
302
303 return null;
304 }
305
306 private Template lookupGenericTypeImpl(ParameterizedType targetType) {
307 Type rawType = targetType.getRawType();
308 return lookupGenericTypeImpl0(targetType, rawType);
309 }
310
311 private Template lookupGenericTypeImpl0(ParameterizedType targetType, Type rawType) {
312 GenericTemplate gtmpl = genericCache.get(rawType);
313 if (gtmpl == null) {
314 return null;
315 }
316
317 Type[] types = targetType.getActualTypeArguments();
318 Template[] tmpls = new Template[types.length];
319 for (int i = 0; i < types.length; ++i) {
320 tmpls[i] = lookup(types[i]);
321 }
322
323 return gtmpl.build(tmpls);
324 }
325
326 private <T> Template<T> lookupGenericInterfaceTypes(ParameterizedType targetType) {
327 Type rawType = targetType.getRawType();
328 Template<T> tmpl = null;
329
330 try {
331 Class<?>[] infTypes = ((Class) rawType).getInterfaces();
332 for (Class<?> infType : infTypes) {
333 tmpl = lookupGenericTypeImpl0(targetType, infType);
334 if (tmpl != null) {
335 return tmpl;
336 }
337 }
338 } catch (ClassCastException e) { // ignore
339 }
340
341 return tmpl;
342 }
343
344 private <T> Template<T> lookupGenericSuperclasses(ParameterizedType targetType) {
345 Type rawType = targetType.getRawType();
346 Template<T> tmpl = null;
347
348 try {
349 Class<?> superClass = ((Class) rawType).getSuperclass();
350 if (superClass == null) {
351 return null;
352 }
353
354 for (; superClass != Object.class; superClass = superClass.getSuperclass()) {
355 tmpl = lookupGenericTypeImpl0(targetType, superClass);
356 if (tmpl != null) {
357 register(targetType, tmpl);
358 return tmpl;
359 }
360 }
361 } catch (ClassCastException e) { // ignore
362 }
363
364 return tmpl;
365 }
366
367 private Template<Type> lookupGenericArrayType(Type targetType) {
368 // TODO GenericArrayType is not a Class<?> => buildArrayTemplate
369 if (! (targetType instanceof GenericArrayType)) {
370 return null;
371 }
372
373 GenericArrayType genericArrayType = (GenericArrayType) targetType;
374 Template<Type> tmpl = lookupGenericArrayTypeImpl(genericArrayType);
375 if (tmpl != null) {
376 return tmpl;
377 }
378
379 try {
380 tmpl = parent.lookupGenericArrayTypeImpl(genericArrayType);
381 if (tmpl != null) {
382 return tmpl;
383 }
384 } catch (NullPointerException e) { // ignore
385 }
386
387 return null;
388 }
389
390 private Template lookupGenericArrayTypeImpl(GenericArrayType genericArrayType) {
391 String genericArrayTypeName = "" + genericArrayType;
392 int dim = genericArrayTypeName.split("\\[").length - 1;
393 if (dim <= 0) {
394 throw new MessageTypeException(
395 String.format("fatal error: type=", genericArrayTypeName));
396 } else if (dim > 1) {
397 throw new UnsupportedOperationException(String.format(
398 "Not implemented template generation of %s", genericArrayTypeName));
399 }
400
401 String genericCompTypeName = "" + genericArrayType.getGenericComponentType();
402 boolean isPrimitiveType = isPrimitiveType(genericCompTypeName);
403 StringBuffer sbuf = new StringBuffer();
404 for (int i = 0; i < dim; i++) {
405 sbuf.append('[');
406 }
407 if (!isPrimitiveType) {
408 sbuf.append('L');
409 sbuf.append(toJvmReferenceTypeName(genericCompTypeName));
410 sbuf.append(';');
411 } else {
412 sbuf.append(toJvmPrimitiveTypeName(genericCompTypeName));
413 }
414
415 String jvmArrayClassName = sbuf.toString();
416 Class jvmArrayClass = null;
417 ClassLoader cl = null;
418 try {
419 cl = Thread.currentThread().getContextClassLoader();
420 if (cl != null) {
421 jvmArrayClass = cl.loadClass(jvmArrayClassName);
422 if (jvmArrayClass != null) {
423 return lookupAfterBuilding(jvmArrayClass);
424 }
425 }
426 } catch (ClassNotFoundException e) {} // ignore
427
428 try {
429 cl = getClass().getClassLoader();
430 if (cl != null) {
431 jvmArrayClass = cl.loadClass(jvmArrayClassName);
432 if (jvmArrayClass != null) {
433 return lookupAfterBuilding(jvmArrayClass);
434 }
435 }
436 } catch (ClassNotFoundException e) {} // ignore
437
438 try {
439 jvmArrayClass = Class.forName(jvmArrayClassName);
440 if (jvmArrayClass != null) {
441 return lookupAfterBuilding(jvmArrayClass);
442 }
443 } catch (ClassNotFoundException e) {} // ignore
444
445 throw new MessageTypeException(String.format(
446 "cannot find template of %s", jvmArrayClassName));
447 }
448
449 private Template<Type> lookupCache(Type targetType) {
450 Template<Type> tmpl = cache.get(targetType);
451 if (tmpl != null) {
452 return tmpl;
453 }
454
455 try {
456 tmpl = parent.lookupCache(targetType);
457 } catch (NullPointerException e) { // ignore
458 }
459 return tmpl;
460 }
461
462 private <T> Template<T> lookupAfterBuilding(Class<T> targetClass) {
463 TemplateBuilder builder = chain.select(targetClass, true);
464 Template<T> tmpl = null;
465 if (builder != null) {
466 // TODO #MN for Android, we should modify here
467 tmpl = chain.getForceBuilder().loadTemplate(targetClass);
468 if (tmpl != null) {
469 register(targetClass, tmpl);
470 return tmpl;
471 }
472 tmpl = buildAndRegister(builder, targetClass, true, null);
473 }
474 return tmpl;
475 }
476
477 private <T> Template<T> lookupInterfaceTypes(Class<T> targetClass) {
478 Class<?>[] infTypes = targetClass.getInterfaces();
479 Template<T> tmpl = null;
480 for (Class<?> infType : infTypes) {
481 tmpl = (Template<T>) cache.get(infType);
482 if (tmpl != null) {
483 register(targetClass, tmpl);
484 return tmpl;
485 } else {
486 try {
487 tmpl = (Template<T>) parent.lookupCache(infType);
488 if (tmpl != null) {
489 register(targetClass, tmpl);
490 return tmpl;
491 }
492 } catch (NullPointerException e) { // ignore
493 }
494 }
495 }
496 return tmpl;
497 }
498
499 private <T> Template<T> lookupSuperclasses(Class<T> targetClass) {
500 Class<?> superClass = targetClass.getSuperclass();
501 Template<T> tmpl = null;
502 if (superClass != null) {
503 for (; superClass != Object.class; superClass = superClass
504 .getSuperclass()) {
505 tmpl = (Template<T>) cache.get(superClass);
506 if (tmpl != null) {
507 register(targetClass, tmpl);
508 return tmpl;
509 } else {
510 try {
511 tmpl = (Template<T>) parent.lookupCache(superClass);
512 if (tmpl != null) {
513 register(targetClass, tmpl);
514 return tmpl;
515 }
516 } catch (NullPointerException e) { // ignore
517 }
518 }
519 }
520 }
521 return tmpl;
522 }
523
524 private <T> Template<T> lookupSuperclassInterfaceTypes(Class<T> targetClass) {
525 Class<?> superClass = targetClass.getSuperclass();
526 Template<T> tmpl = null;
527 if (superClass != null) {
528 for (; superClass != Object.class; superClass = superClass.getSuperclass()) {
529 tmpl = (Template<T>) lookupInterfaceTypes(superClass);
530 if (tmpl != null) {
531 register(targetClass, tmpl);
532 return tmpl;
533 } else {
534 try {
535 tmpl = (Template<T>) parent.lookupCache(superClass);
536 if (tmpl != null) {
537 register(targetClass, tmpl);
538 return tmpl;
539 }
540 } catch (NullPointerException e) { // ignore
541 }
542 }
543 }
544 }
545 return tmpl;
546 }
547
548 private synchronized Template buildAndRegister(TemplateBuilder builder,
549 final Class targetClass, final boolean hasAnnotation,
550 final FieldList flist) {
551 Template newTmpl = null;
552 Template oldTmpl = null;
553 try {
554 if (cache.containsKey(targetClass)) {
555 oldTmpl = cache.get(targetClass);
556 }
557 newTmpl = new TemplateReference(this, targetClass);
558 cache.put(targetClass, newTmpl);
559 if (builder == null) {
560 builder = chain.select(targetClass, hasAnnotation);
561 }
562 newTmpl = flist != null ?
563 builder.buildTemplate(targetClass, flist) : builder.buildTemplate(targetClass);
564 return newTmpl;
565 } catch (Exception e) {
566 if (oldTmpl != null) {
567 cache.put(targetClass, oldTmpl);
568 } else {
569 cache.remove(targetClass);
570 }
571 newTmpl = null;
572 if (e instanceof MessageTypeException) {
573 throw (MessageTypeException) e;
574 } else {
575 throw new MessageTypeException(e);
576 }
577 } finally {
578 if (newTmpl != null) {
579 cache.put(targetClass, newTmpl);
580 }
581 }
582 }
583
584 private static boolean isPrimitiveType(String genericCompTypeName) {
585 return (genericCompTypeName.equals("byte")
586 || genericCompTypeName.equals("short")
587 || genericCompTypeName.equals("int")
588 || genericCompTypeName.equals("long")
589 || genericCompTypeName.equals("float")
590 || genericCompTypeName.equals("double")
591 || genericCompTypeName.equals("boolean")
592 || genericCompTypeName.equals("char"));
593 }
594
595 private static String toJvmReferenceTypeName(String typeName) {
596 // delete "class " from class name
597 // e.g. "class Foo" to "Foo" by this method
598 return typeName.substring(6);
599 }
600
601 private static String toJvmPrimitiveTypeName(String typeName) {
602 if (typeName.equals("byte")) {
603 return "B";
604 } else if (typeName.equals("short")) {
605 return "S";
606 } else if (typeName.equals("int")) {
607 return "I";
608 } else if (typeName.equals("long")) {
609 return "J";
610 } else if (typeName.equals("float")) {
611 return "F";
612 } else if (typeName.equals("double")) {
613 return "D";
614 } else if (typeName.equals("boolean")) {
615 return "Z";
616 } else if (typeName.equals("char")) {
617 return "C";
618 } else {
619 throw new MessageTypeException(String.format(
620 "fatal error: type=%s", typeName));
621 }
622 }
623 }