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 }