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