1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48 package org.exolab.castor.mapping.loader;
49
50 import java.io.Serializable;
51 import java.lang.reflect.Array;
52 import java.lang.reflect.Constructor;
53 import java.lang.reflect.Field;
54 import java.lang.reflect.Method;
55 import java.lang.reflect.Modifier;
56 import java.util.ArrayList;
57 import java.util.HashMap;
58 import java.util.Iterator;
59 import java.util.List;
60 import java.util.Enumeration;
61 import java.util.Map;
62 import java.util.Properties;
63
64
65 import org.castor.xml.InternalContext;
66 import org.castor.xml.AbstractInternalContext;
67 import org.castor.core.util.Messages;
68 import org.exolab.castor.mapping.ClassDescriptor;
69 import org.exolab.castor.mapping.ClonableFieldHandler;
70 import org.exolab.castor.mapping.ClonableFieldHandlerMarker;
71 import org.exolab.castor.mapping.CollectionHandler;
72 import org.exolab.castor.mapping.ConfigurableFieldHandler;
73 import org.exolab.castor.mapping.ExtendedFieldHandler;
74 import org.exolab.castor.mapping.FieldDescriptor;
75 import org.exolab.castor.mapping.FieldHandler;
76 import org.exolab.castor.mapping.GeneralizedFieldHandler;
77 import org.exolab.castor.mapping.MapItem;
78 import org.exolab.castor.mapping.MappingException;
79 import org.exolab.castor.mapping.ValidityException;
80 import org.exolab.castor.mapping.handlers.EnumFieldHandler;
81 import org.exolab.castor.mapping.handlers.TransientFieldHandler;
82 import org.exolab.castor.mapping.xml.ClassChoice;
83 import org.exolab.castor.mapping.xml.FieldHandlerDef;
84 import org.exolab.castor.mapping.xml.MappingRoot;
85 import org.exolab.castor.mapping.xml.ClassMapping;
86 import org.exolab.castor.mapping.xml.FieldMapping;
87 import org.exolab.castor.mapping.xml.Param;
88
89
90
91
92
93
94
95
96
97
98 public abstract class AbstractMappingLoader extends AbstractMappingLoader2 {
99
100
101 private static final String ADD_METHOD_PREFIX = "add";
102
103
104 private static final String ENUM_METHOD_PREFIX = "enum";
105
106
107 private static final String ITER_METHOD_PREFIX = "iterate";
108
109
110 private static final String GET_METHOD_PREFIX = "get";
111
112
113 private static final String IS_METHOD_PREFIX = "is";
114
115
116 private static final String SET_METHOD_PREFIX = "set";
117
118
119 private static final String CREATE_METHOD_PREFIX = "create";
120
121
122 private static final String HAS_METHOD_PREFIX = "has";
123
124
125 private static final String DELETE_METHOD_PREFIX = "delete";
126
127
128 protected static final Class<?>[] EMPTY_ARGS = new Class[0];
129
130
131
132 protected static final Class<?>[] STRING_ARG = {String.class};
133
134
135 protected static final String VALUE_OF = "valueOf";
136
137
138 protected static final String NAME = "name";
139
140
141
142
143
144 private InternalContext _internalContext;
145
146
147 private final Map<String, FieldHandler> _fieldHandlers = new HashMap<String, FieldHandler>();
148
149
150
151
152
153
154 protected AbstractMappingLoader(final ClassLoader loader) {
155 super(loader);
156 }
157
158
159
160
161 public final String getSourceType() {
162 return "CastorXmlMapping";
163 }
164
165
166
167
168
169
170
171
172 public abstract void loadMapping(final MappingRoot mapping, final Object param)
173 throws MappingException;
174
175
176
177
178
179
180
181
182
183 protected void createFieldHandlers(final MappingRoot mapping)
184 throws MappingException {
185 Enumeration<? extends FieldHandlerDef> enumeration = mapping.enumerateFieldHandlerDef();
186 while (enumeration.hasMoreElements()) {
187 FieldHandlerDef def = enumeration.nextElement();
188
189 String name = def.getName();
190
191 if (_fieldHandlers.containsKey(name)) {
192 throw new MappingException(Messages.format("mapping.dupFieldHandler", name));
193 }
194
195
196 Class<?> clazz = resolveType(def.getClazz());
197 FieldHandler fieldHandler = null;
198 try {
199 if (!FieldHandler.class.isAssignableFrom(clazz)) {
200 throw new MappingException(Messages.format("mapping.classNotFieldHandler",
201 name, def.getClazz()));
202 }
203 fieldHandler = (FieldHandler) clazz.newInstance();
204 _fieldHandlers.put(name, fieldHandler);
205 } catch (InstantiationException e) {
206 throw new MappingException(e);
207 } catch (IllegalAccessException e) {
208 throw new MappingException(e);
209 }
210
211
212 configureFieldHandler(def, fieldHandler);
213
214 }
215 }
216
217
218
219
220
221 private void configureFieldHandler(final FieldHandlerDef def, final FieldHandler fieldHandler)
222 throws MappingException {
223
224
225 Properties params = new Properties();
226 Enumeration<? extends Param> enumerateParam = def.enumerateParam();
227 while (enumerateParam.hasMoreElements()) {
228 Param par = enumerateParam.nextElement();
229 params.put(par.getName(), par.getValue());
230 }
231
232
233
234 if (params.size() > 0) {
235 if (!ConfigurableFieldHandler.class.isAssignableFrom(fieldHandler.getClass())) {
236 throw new MappingException(Messages.format("mapping.classNotConfigurableFieldHandler",
237 def.getName(), def.getClazz()));
238 }
239
240
241 try {
242 ((ConfigurableFieldHandler)fieldHandler).setConfiguration(params);
243 } catch (ValidityException e) {
244 throw new MappingException(Messages.format("mapping.invalidFieldHandlerConfig",
245 def.getName(), e.getMessage()), e);
246 }
247 }
248 }
249
250 protected final void createClassDescriptors(final MappingRoot mapping)
251 throws MappingException {
252
253
254 Enumeration<? extends ClassMapping> enumeration = mapping.enumerateClassMapping();
255
256 List<ClassMapping> retryList = new ArrayList<ClassMapping>();
257 while (enumeration.hasMoreElements()) {
258 ClassMapping clsMap = enumeration.nextElement();
259 try {
260 ClassDescriptor clsDesc = createClassDescriptor(clsMap);
261 if (clsDesc != null) {
262 addDescriptor(clsDesc);
263 }
264 } catch (MappingException mx) {
265
266 retryList.add(clsMap);
267 continue;
268 }
269 }
270
271
272
273 for (ClassMapping classMapping : retryList) {
274 ClassDescriptor clsDesc = createClassDescriptor(classMapping);
275 if (clsDesc != null) {
276 addDescriptor(clsDesc);
277 }
278 }
279
280
281 for (ClassDescriptor classDescriptor : getDescriptors()) {
282 resolveRelations(classDescriptor);
283 }
284 }
285
286 protected abstract ClassDescriptor createClassDescriptor(final ClassMapping clsMap)
287 throws MappingException;
288
289
290
291
292
293
294
295
296
297
298
299
300
301 protected final ClassDescriptor getExtended(final ClassMapping clsMap,
302 final Class<?> javaClass) throws MappingException {
303 if (clsMap.getExtends() == null) {
304 return null;
305 }
306
307 ClassMapping mapping = (ClassMapping) clsMap.getExtends();
308 Class<?> type = resolveType(mapping.getName());
309 ClassDescriptor result = getDescriptor(type.getName());
310
311 if (result == null) {
312 throw new MappingException(
313 "mapping.extendsMissing", mapping, javaClass.getName());
314 }
315
316 if (!result.getJavaClass().isAssignableFrom(javaClass)) {
317 throw new MappingException("mapping.classDoesNotExtend",
318 javaClass.getName(), result.getJavaClass().getName());
319 }
320
321 return result;
322 }
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337 protected final ClassDescriptor getDepended(final ClassMapping clsMap,
338 final Class<?> javaClass) throws MappingException {
339 if (clsMap.getDepends() == null) {
340 return null;
341 }
342
343 ClassMapping mapping = (ClassMapping) clsMap.getDepends();
344 Class<?> type = resolveType(mapping.getName());
345 ClassDescriptor result = getDescriptor(type.getName());
346
347 if (result == null) {
348 throw new MappingException(
349 "Depends not found: " + mapping + " " + javaClass.getName());
350 }
351
352 return result;
353 }
354
355
356
357
358
359
360
361
362
363 protected final void checkFieldNameDuplicates(final FieldDescriptor[] fields,
364 final Class<?> cls) throws MappingException {
365 for (int i = 0; i < fields.length - 1; i++) {
366 String fieldName = fields[i].getFieldName();
367 for (int j = i + 1; j < fields.length; j++) {
368 if (fieldName.equals(fields[j].getFieldName())) {
369 throw new MappingException("The field " + fieldName
370 + " appears twice in the descriptor for " + cls.getName());
371 }
372 }
373 }
374 }
375
376 protected abstract void resolveRelations(final ClassDescriptor clsDesc);
377
378
379
380
381
382
383
384
385
386 protected final Class<?> resolveType(final String typeName)
387 throws MappingException {
388 try {
389 return Types.typeFromName(getClassLoader(), typeName);
390 } catch (ClassNotFoundException ex) {
391 throw new MappingException("mapping.classNotFound", typeName);
392 }
393 }
394
395
396
397
398
399
400
401
402
403
404
405
406 protected final FieldDescriptorImpl[] createFieldDescriptors(final ClassMapping clsMap,
407 final Class<?> javaClass) throws MappingException {
408 FieldMapping[] fldMap = null;
409
410 if (clsMap.getClassChoice() != null) {
411 fldMap = clsMap.getClassChoice().getFieldMapping();
412 }
413
414 if ((fldMap == null) || (fldMap.length == 0)) {
415 return new FieldDescriptorImpl[0];
416 }
417
418 FieldDescriptorImpl[] fields = new FieldDescriptorImpl[fldMap.length];
419 for (int i = 0; i < fldMap.length; i++) {
420 fields[i] = createFieldDesc(javaClass, fldMap[i]);
421
422
423 fields[i].setIdentity(fldMap[i].getIdentity());
424 }
425
426 return fields;
427 }
428
429
430
431
432
433
434
435
436
437 protected final ClassMapping getOrigin(final ClassMapping clsMap) {
438 ClassMapping result = clsMap;
439
440 while (result.getExtends() != null) {
441 result = (ClassMapping) result.getExtends();
442 }
443
444 return result;
445 }
446
447 protected final FieldDescriptor[] divideFieldDescriptors(final FieldDescriptor[] fields,
448 final String[] ids, final FieldDescriptor[] identities) {
449 List<FieldDescriptor> fieldList = new ArrayList<FieldDescriptor>(fields.length);
450
451 for (int i = 0; i < fields.length; i++) {
452 FieldDescriptor field = fields[i];
453 final int index = getIdColumnIndex(field, ids);
454 if (index == -1) {
455
456 fieldList.add(field);
457 } else {
458 if (field instanceof FieldDescriptorImpl) {
459 ((FieldDescriptorImpl) field).setRequired(true);
460 }
461 if (field.getHandler() instanceof FieldHandlerImpl) {
462 ((FieldHandlerImpl) field.getHandler()).setRequired(true);
463 }
464
465 identities[index] = field;
466 }
467 }
468
469
470 FieldDescriptor[] result = new FieldDescriptor[fieldList.size()];
471 return fieldList.toArray(result);
472 }
473
474
475
476
477
478
479
480
481
482
483 protected int getIdColumnIndex(FieldDescriptor field, String[] ids) {
484 for (int i = 0; i < ids.length; i++) {
485 if (field.getFieldName().equals(ids[i])) {
486 return i;
487 }
488 }
489 return -1;
490 }
491
492
493
494
495
496
497
498
499
500
501
502
503 protected FieldDescriptorImpl createFieldDesc(final Class<?> javaClass,
504 final FieldMapping fieldMap) throws MappingException {
505 String fieldName = fieldMap.getName();
506
507
508 Class<?> fieldType = null;
509 if (fieldMap.getType() != null) {
510 fieldType = resolveType(fieldMap.getType());
511 }
512
513
514
515 CollectionHandler collectionHandler = null;
516 if (fieldMap.getCollection() != null) {
517 String colTypeName = fieldMap.getCollection().toString();
518 Class<?> collectionType = CollectionHandlers.getCollectionType(colTypeName);
519 collectionHandler = CollectionHandlers.getHandler(collectionType);
520 }
521
522 TypeInfo typeInfo = getTypeInfo(fieldType, collectionHandler, fieldMap);
523
524 ExtendedFieldHandler exfHandler = null;
525 FieldHandler handler = null;
526
527
528 if (fieldMap.getHandler() != null) {
529 handler = getFieldHandler(fieldMap);
530
531
532 if (handler instanceof ExtendedFieldHandler) {
533 exfHandler = (ExtendedFieldHandler) handler;
534 }
535
536
537
538
539
540 collectionHandler = typeInfo.getCollectionHandler();
541 typeInfo.setCollectionHandler(null);
542 handler = new FieldHandlerImpl(handler, typeInfo);
543 typeInfo.setCollectionHandler(collectionHandler);
544
545 }
546
547 boolean generalized = (exfHandler instanceof GeneralizedFieldHandler);
548
549
550
551 if (generalized) {
552 fieldType = ((GeneralizedFieldHandler)exfHandler).getFieldType();
553 }
554
555 if (generalized || (handler == null)) {
556
557 FieldHandler custom = handler;
558 TypeInfoReference typeInfoRef = new TypeInfoReference();
559 typeInfoRef.typeInfo = typeInfo;
560 handler = createFieldHandler(javaClass, fieldType, fieldMap, typeInfoRef);
561 if (custom != null) {
562 ((GeneralizedFieldHandler) exfHandler).setFieldHandler(handler);
563 handler = custom;
564 } else {
565 boolean isTypeSafeEnum = false;
566
567 if ((fieldType != null) && !isPrimitive(fieldType)) {
568 if (!hasPublicDefaultConstructor(fieldType)) {
569 Method method = getStaticValueOfMethod(fieldType);
570 if (method != null) {
571 handler = new EnumFieldHandler(fieldType, handler, method);
572 typeInfo.setImmutable(true);
573 isTypeSafeEnum = true;
574 }
575 }
576 }
577
578 if (!isTypeSafeEnum) { typeInfo = typeInfoRef.typeInfo; }
579 }
580 }
581
582 FieldDescriptorImpl fieldDesc = new FieldDescriptorImpl(
583 fieldName, typeInfo, handler, fieldMap.getTransient());
584
585 fieldDesc.setRequired(fieldMap.getRequired());
586
587
588 fieldDesc.setCollection(fieldMap.getCollection());
589
590
591 fieldDesc.setComparator(fieldMap.getComparator());
592 fieldDesc.setCreateMethod(fieldMap.getCreateMethod());
593 fieldDesc.setGetMethod(fieldMap.getGetMethod());
594 fieldDesc.setSetMethod(fieldMap.getSetMethod());
595
596
597 fieldDesc.setDirect(fieldMap.getDirect());
598
599
600 fieldDesc.setLazy(fieldMap.isLazy());
601
602
603 if (exfHandler != null) {
604 ((FieldHandlerFriend) exfHandler).setFieldDescriptor(fieldDesc);
605 }
606
607 return fieldDesc;
608 }
609
610 private FieldHandler<?> getFieldHandler(final FieldMapping fieldMap)
611 throws MappingException {
612
613
614
615 FieldHandler<?> handler = _fieldHandlers.get(fieldMap.getHandler());
616 if (handler != null) {
617
618 if (!(handler instanceof ClonableFieldHandler || handler instanceof ClonableFieldHandlerMarker)) {
619 return handler;
620 }
621
622 String methodName = "copyFieldHandler";
623 if (handler instanceof ClonableFieldHandler) {
624 methodName = "copyInstance";
625 }
626
627 FieldHandler<?> clonedHandler = handler;
628 Class<?> classToClone = handler.getClass();
629 try {
630 Method method;
631 method = classToClone.getMethod(methodName, (Class[]) null);
632 clonedHandler = (FieldHandler<?>) method.invoke(handler, (Object[]) null);
633 return clonedHandler;
634 } catch (Exception e) {
635 String err = "The class '" + classToClone.getName() + "' must implement the ClonableFieldHandlerMarker interface.";
636 throw new MappingException(err, e);
637 }
638 }
639
640 Class<?> handlerClass = null;
641 handlerClass = resolveType(fieldMap.getHandler());
642
643 if (!FieldHandler.class.isAssignableFrom(handlerClass)) {
644 String err = "The class '" + fieldMap.getHandler() + "' must implement "
645 + FieldHandler.class.getName();
646 throw new MappingException(err);
647 }
648
649
650
651 try {
652 Constructor<?> constructor = handlerClass.getConstructor(new Class[0]);
653 return (FieldHandler<?>) constructor.newInstance(new Object[0]);
654 } catch (Exception ex) {
655 String err = "The class '" + handlerClass.getName()
656 + "' must have a default public constructor.";
657 throw new MappingException(err);
658 }
659 }
660
661
662
663
664
665
666
667 private boolean hasPublicDefaultConstructor(final Class<?> type) {
668 try {
669 Constructor<?> cons = type.getConstructor(EMPTY_ARGS);
670 return Modifier.isPublic(cons.getModifiers());
671 } catch (NoSuchMethodException ex) {
672 return false;
673 }
674 }
675
676
677
678
679
680
681
682
683 private Method getStaticValueOfMethod(final Class<?> type) {
684 try {
685 Method method = type.getMethod(VALUE_OF, STRING_ARG);
686 Class<?> returnType = method.getReturnType();
687 if (returnType == null) {
688 return null;
689 }
690 if (!type.isAssignableFrom(returnType)) {
691 return null;
692 }
693 if (!Modifier.isStatic(method.getModifiers())) {
694 return null;
695 }
696 return method;
697 } catch (NoSuchMethodException ex) {
698 return null;
699 }
700 }
701
702
703
704
705
706
707
708
709
710 protected final FieldHandler createFieldHandler(Class<?> javaClass, Class<?> fldType,
711 final FieldMapping fldMap,
712 final TypeInfoReference typeInfoRef) throws MappingException {
713
714 if (fldMap.getTransient()) {
715 return new TransientFieldHandler();
716 }
717
718 Class<?> collectionType = null;
719 CollectionHandler collectionHandler = null;
720 boolean colRequireGetSet = true;
721
722 String fieldName = fldMap.getName();
723
724
725
726 if (fldMap.getCollection() != null) {
727 String colTypeName = fldMap.getCollection().toString();
728 collectionType = CollectionHandlers.getCollectionType(colTypeName);
729 collectionHandler = CollectionHandlers.getHandler(collectionType);
730 colRequireGetSet = CollectionHandlers.isGetSetCollection(collectionType);
731 if (collectionType == Object[].class) {
732 if (fldType == null) {
733 String msg = "'type' is a required attribute for field that are "
734 + "array collections: " + fieldName;
735 throw new MappingException(msg);
736 }
737 Object obj = Array.newInstance(fldType, 0);
738 collectionType = obj.getClass();
739 }
740 }
741
742
743 FieldHandlerImpl handler = null;
744
745
746 if (fldMap.getDirect()) {
747
748 Field field = findField(javaClass, fieldName, (collectionType == null ? fldType : collectionType));
749 if (field == null) {
750 throw new MappingException(
751 "mapping.fieldNotAccessible", fieldName, javaClass.getName());
752 }
753 if (fldType == null) {
754 fldType = field.getType();
755 }
756
757 typeInfoRef.typeInfo = getTypeInfo(fldType, collectionHandler, fldMap);
758
759 handler = new FieldHandlerImpl(field, typeInfoRef.typeInfo);
760 } else if ((fldMap.getGetMethod() == null) && (fldMap.getSetMethod() == null)) {
761
762 if (fieldName == null) {
763 throw new MappingException(
764 "mapping.missingFieldName", javaClass.getName());
765 }
766
767 List<Method> getSequence = new ArrayList<Method>();
768 List<Method> setSequence = new ArrayList<Method>();
769 Method getMethod = null;
770 Method setMethod = null;
771
772
773
774 try {
775
776 while (true) {
777 int point = fieldName.indexOf('.');
778 if (point < 0) { break; }
779
780 String parentField = fieldName.substring(0, point);
781
782
783 String methodName = GET_METHOD_PREFIX + capitalize(parentField);
784 Method method = javaClass.getMethod(methodName, (Class[]) null);
785 if (isAbstractOrStatic(method)) {
786 throw new MappingException("mapping.accessorNotAccessible",
787 methodName, javaClass.getName());
788 }
789 getSequence.add(method);
790
791 Class<?> nextClass = method.getReturnType();
792
793
794 try {
795 methodName = SET_METHOD_PREFIX + capitalize(parentField);
796 Class<?>[] types = new Class[] {nextClass};
797 method = javaClass.getMethod(methodName, types);
798 if (isAbstractOrStatic(method)) { method = null; }
799 } catch (Exception ex) {
800 method = null;
801 }
802 setSequence.add(method);
803
804 javaClass = nextClass;
805 fieldName = fieldName.substring(point + 1);
806 }
807
808
809 String methodName = GET_METHOD_PREFIX + capitalize( fieldName );
810 Class<?> returnType = (collectionType == null) ? fldType : collectionType;
811 getMethod = findAccessor(javaClass, methodName, returnType, true);
812
813
814 if (getMethod == null) {
815 if ((fldType == Boolean.class) || (fldType == Boolean.TYPE)) {
816 methodName = IS_METHOD_PREFIX + capitalize(fieldName);
817 getMethod = findAccessor(javaClass, methodName, returnType, true);
818 }
819 }
820 } catch (MappingException ex) {
821 throw ex;
822 } catch (Exception ex) {
823
824 }
825
826 if (getMethod == null) {
827 String getAccessor = GET_METHOD_PREFIX + capitalize(fieldName);
828 String isAccessor = IS_METHOD_PREFIX + capitalize(fieldName);
829 throw new MappingException("mapping.accessorNotFound",
830 getAccessor + "/" + isAccessor,
831 (collectionType == null ? fldType : collectionType),
832 javaClass.getName());
833 }
834
835 if ((fldType == null) && (collectionType == null)) {
836 fldType = getMethod.getReturnType();
837 }
838
839
840 String methodName = SET_METHOD_PREFIX + capitalize(fieldName);
841 setMethod = findAccessor(javaClass, methodName,
842 (collectionType == null ? fldType : collectionType), false);
843
844
845
846 if ((setMethod == null) && (collectionType != null) && colRequireGetSet) {
847 throw new MappingException("mapping.accessorNotFound", methodName,
848 (collectionType == null ? fldType : collectionType), javaClass.getName());
849 }
850
851 typeInfoRef.typeInfo = getTypeInfo(fldType, collectionHandler, fldMap);
852
853 fieldName = fldMap.getName();
854 if (fieldName == null) {
855 if (getMethod == null) {
856 fieldName = setMethod.getName();
857 } else {
858 fieldName = getMethod.getName();
859 }
860 }
861
862
863 Method[] getArray = null;
864 Method[] setArray = null;
865 if (getSequence.size() > 0) {
866 getArray = new Method[getSequence.size()];
867 getArray = getSequence.toArray(getArray);
868 setArray = new Method[setSequence.size()];
869 setArray = setSequence.toArray(setArray);
870 }
871
872
873 handler = new FieldHandlerImpl(fieldName, getArray, setArray,
874 getMethod, setMethod, typeInfoRef.typeInfo);
875
876 if (setMethod != null) {
877 if (setMethod.getName().startsWith(ADD_METHOD_PREFIX)) {
878 handler.setAddMethod(setMethod);
879 }
880 }
881 } else {
882 Method getMethod = null;
883 Method setMethod = null;
884
885
886 if (fldMap.getGetMethod() != null) {
887 Class<?> rtype = fldType;
888 if (collectionType != null) {
889 String methodName = fldMap.getGetMethod();
890 if (methodName.startsWith(ENUM_METHOD_PREFIX)) {
891
892 rtype = Enumeration.class;
893 } else if (methodName.startsWith(ITER_METHOD_PREFIX)) {
894
895 rtype = Iterator.class;
896 } else {
897 rtype = collectionType;
898 }
899 }
900
901 getMethod = findAccessor(javaClass, fldMap.getGetMethod(), rtype, true);
902 if (getMethod == null) {
903 throw new MappingException("mapping.accessorNotFound",
904 fldMap.getGetMethod(), rtype, javaClass.getName());
905 }
906
907 if ((fldType == null) && (collectionType == null)) {
908 fldType = getMethod.getReturnType();
909 }
910 }
911
912
913 if (fldMap.getSetMethod() != null) {
914 String methodName = fldMap.getSetMethod();
915 Class<?> type = fldType;
916 if (collectionType != null) {
917 if (!methodName.startsWith(ADD_METHOD_PREFIX)) {
918 type = collectionType;
919 }
920 }
921
922
923 if (methodName.startsWith("%")) {
924
925 int index = 0;
926
927 String temp = methodName.substring(1);
928 try {
929 index = Integer.parseInt(temp);
930 } catch(NumberFormatException ex) {
931 throw new MappingException("mapping.invalidParameterIndex", temp);
932 }
933
934 if ((index < 1) || (index > 9)) {
935 throw new MappingException("mapping.invalidParameterIndex", temp);
936 }
937 } else {
938 setMethod = findAccessor(javaClass, methodName, type , false);
939 if (setMethod == null) {
940 throw new MappingException("mapping.accessorNotFound",
941 methodName, type, javaClass.getName());
942 }
943
944 if (fldType == null) {
945 fldType = setMethod.getParameterTypes()[0];
946 }
947 }
948 }
949
950 typeInfoRef.typeInfo = getTypeInfo(fldType, collectionHandler, fldMap);
951
952 fieldName = fldMap.getName();
953 if (fieldName == null) {
954 if (getMethod == null) {
955 fieldName = setMethod.getName();
956 } else {
957 fieldName = getMethod.getName();
958 }
959 }
960
961
962 handler = new FieldHandlerImpl(fieldName, null, null,
963 getMethod, setMethod, typeInfoRef.typeInfo);
964
965 if (setMethod != null) {
966 if (setMethod.getName().startsWith(ADD_METHOD_PREFIX)) {
967 handler.setAddMethod(setMethod);
968 }
969 }
970 }
971
972
973 String methodName = fldMap.getCreateMethod();
974 if (methodName != null) {
975 try {
976 Method method = javaClass.getMethod(methodName, (Class[]) null);
977 handler.setCreateMethod(method);
978 } catch (Exception ex) {
979 throw new MappingException("mapping.createMethodNotFound",
980 methodName, javaClass.getName());
981 }
982 } else if ((fieldName != null) && !Types.isSimpleType(fldType)) {
983 try {
984 methodName = CREATE_METHOD_PREFIX + capitalize(fieldName);
985 Method method = javaClass.getMethod(methodName, (Class[]) null);
986 handler.setCreateMethod(method);
987 } catch (Exception ex) {
988
989 }
990 }
991
992
993 if (fieldName != null) {
994 try {
995 methodName = fldMap.getHasMethod();
996 if (methodName == null) {
997 methodName = HAS_METHOD_PREFIX + capitalize(fieldName);
998 }
999 Method hasMethod = javaClass.getMethod(methodName, (Class[]) null);
1000
1001 if ((hasMethod.getModifiers() & Modifier.STATIC) != 0) {
1002 hasMethod = null;
1003 }
1004
1005 Method deleteMethod = null;
1006 try {
1007 methodName = DELETE_METHOD_PREFIX + capitalize(fieldName);
1008 deleteMethod = javaClass.getMethod(methodName, (Class[]) null );
1009 if ((deleteMethod.getModifiers() & Modifier.STATIC) != 0) {
1010 deleteMethod = null;
1011 }
1012 } catch (Exception ex) {
1013
1014 }
1015
1016 handler.setHasDeleteMethod(hasMethod, deleteMethod);
1017 } catch (Exception ex) {
1018
1019 }
1020 }
1021
1022 return handler;
1023 }
1024
1025 private static boolean isAbstract(final Class<?> cls) {
1026 return ((cls.getModifiers() & Modifier.ABSTRACT) != 0);
1027 }
1028
1029 private static boolean isAbstractOrStatic(final Method method) {
1030 return ((method.getModifiers() & Modifier.ABSTRACT) != 0)
1031 || ((method.getModifiers() & Modifier.STATIC) != 0);
1032 }
1033
1034 protected TypeInfo getTypeInfo(final Class fieldType,
1035 final CollectionHandler colHandler,
1036 final FieldMapping fieldMap) throws MappingException {
1037 return new TypeInfo(Types.typeFromPrimitive(fieldType), null, null,
1038 fieldMap.getRequired(), null, colHandler, false);
1039 }
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052 private final Field findField(final Class<?> javaClass, final String fieldName,
1053 Class<?> fieldType) throws MappingException {
1054 try {
1055
1056
1057 Field field = javaClass.getField(fieldName);
1058 if ((field.getModifiers() != Modifier.PUBLIC)
1059 && (field.getModifiers() != (Modifier.PUBLIC | Modifier.VOLATILE))) {
1060 throw new MappingException(
1061 "mapping.fieldNotAccessible", fieldName, javaClass.getName());
1062 }
1063
1064 if (fieldType == null) {
1065 fieldType = Types.typeFromPrimitive(field.getType());
1066 } else {
1067 Class<?> ft1 = Types.typeFromPrimitive(fieldType);
1068 Class<?> ft2 = Types.typeFromPrimitive(field.getType());
1069 if ((ft1 != ft2) && (fieldType != Serializable.class)) {
1070 throw new MappingException(
1071 "mapping.fieldTypeMismatch", field, fieldType.getName());
1072 }
1073 }
1074 return field;
1075 } catch (NoSuchFieldException ex) {
1076 return null;
1077 } catch (SecurityException ex) {
1078 return null;
1079 }
1080 }
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094 public static final Method findAccessor(final Class<?> javaClass,
1095 final String methodName, Class<?> fieldType,
1096 final boolean getMethod) throws MappingException {
1097 try {
1098 Method method = null;
1099
1100 if (getMethod) {
1101
1102
1103 method = javaClass.getMethod(methodName, new Class[0]);
1104
1105
1106
1107
1108 if (javaClass == MapItem.class) {
1109 if (methodName.equals("getKey")) { return method; }
1110 if (methodName.equals("getValue")) { return method; }
1111 }
1112
1113 if (fieldType == null) {
1114 fieldType = Types.typeFromPrimitive(method.getReturnType());
1115 } else {
1116 fieldType = Types.typeFromPrimitive(fieldType);
1117 Class<?> returnType = Types.typeFromPrimitive(method.getReturnType());
1118
1119
1120
1121
1122 if (fieldType.isInterface()
1123 || ((fieldType.getModifiers() & Modifier.ABSTRACT) != 0)
1124 || (fieldType == java.io.Serializable.class)) {
1125
1126 if (!fieldType.isAssignableFrom(returnType)) {
1127 throw new MappingException(
1128 "mapping.accessorReturnTypeMismatch",
1129 method, fieldType.getName());
1130 }
1131 } else {
1132 if (!returnType.isAssignableFrom(fieldType)) {
1133 throw new MappingException(
1134 "mapping.accessorReturnTypeMismatch",
1135 method, fieldType.getName());
1136 }
1137 }
1138 }
1139 } else {
1140
1141
1142
1143
1144 Class<?> fieldTypePrimitive = null;
1145 if (fieldType != null) {
1146 fieldTypePrimitive = Types.typeFromPrimitive(fieldType);
1147 try {
1148 method = javaClass.getMethod(methodName, new Class[] {fieldType});
1149 } catch (Exception ex) {
1150 try {
1151 method = javaClass.getMethod(
1152 methodName, new Class[] {fieldTypePrimitive});
1153 } catch (Exception ex2) {
1154
1155 }
1156 }
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176 }
1177
1178 if (method == null) {
1179 Method[] methods = javaClass.getMethods();
1180 for (int i = 0; i < methods.length; ++i) {
1181 if (methods[i].getName().equals(methodName)) {
1182 Class<?>[] paramTypes = methods[i].getParameterTypes();
1183 if (paramTypes.length != 1) {
1184 continue;
1185 }
1186
1187 Class<?> paramType = Types.typeFromPrimitive(paramTypes[0]);
1188
1189 if (fieldType == null) {
1190 method = methods[i];
1191 break;
1192 } else if (paramType.isAssignableFrom(fieldTypePrimitive)) {
1193 method = methods[i];
1194 break;
1195 } else if (fieldType.isInterface() || isAbstract(fieldType)) {
1196 if (fieldTypePrimitive.isAssignableFrom(paramType)) {
1197 method = methods[i];
1198 break;
1199 }
1200 }
1201 }
1202 }
1203
1204 if (method == null) {
1205 return null;
1206 }
1207 }
1208 }
1209
1210
1211
1212 if ((method.getModifiers() & Modifier.STATIC) != 0) {
1213 throw new MappingException(
1214 "mapping.accessorNotAccessible", methodName, javaClass.getName());
1215 }
1216 return method;
1217 } catch (MappingException ex) {
1218 throw ex;
1219 } catch (Exception ex) {
1220 return null;
1221 }
1222 }
1223
1224 private static final String capitalize(final String name) {
1225 char first = name.charAt(0);
1226 if (Character.isUpperCase(first)) {
1227 return name;
1228 }
1229 return Character.toUpperCase(first) + name.substring(1);
1230 }
1231
1232
1233
1234
1235
1236
1237
1238
1239 public static final String[] getIdentityColumnNames(final String[] ids,
1240 final ClassMapping clsMap) {
1241
1242 String[] idNames = ids;
1243
1244 if ((ids == null) || (ids.length == 0)) {
1245 ClassChoice classChoice = clsMap.getClassChoice();
1246 if (classChoice == null) {
1247 classChoice = new ClassChoice();
1248 }
1249
1250 FieldMapping[] fieldMappings = classChoice.getFieldMapping();
1251
1252 List<String> idNamesList = new ArrayList<String>();
1253 for (FieldMapping fieldMapping : fieldMappings) {
1254 if (fieldMapping.getIdentity() == true) {
1255 idNamesList.add(fieldMapping.getName());
1256 }
1257 }
1258
1259 if (!idNamesList.isEmpty()) {
1260 idNames = new String[idNamesList.size()];
1261 idNames = idNamesList.toArray(idNames);
1262 }
1263 }
1264
1265 return idNames;
1266 }
1267
1268
1269
1270
1271
1272
1273
1274 protected static final boolean isPrimitive(final Class<?> type) {
1275 if (type.isPrimitive()) { return true; }
1276 if ((type == Boolean.class) || (type == Character.class)) { return true; }
1277 return (type.getSuperclass() == Number.class);
1278 }
1279
1280
1281
1282
1283
1284 public class TypeInfoReference {
1285 public TypeInfo typeInfo = null;
1286 }
1287
1288 public void setInternalContext(final InternalContext internalContext) {
1289 _internalContext = internalContext;
1290 }
1291
1292 public InternalContext getInternalContext() {
1293 return _internalContext;
1294 }
1295
1296 }