/** * Parse the sql type attribute to build an array of types, needed to support whitespace inside * parameterized types (see Bug 1045). */ protected String[] getSqlTypes(final FieldMapping fieldMap) { if (fieldMap.getSql() == null) { return new String[0]; } String sqlType = fieldMap.getSql().getType(); if (sqlType == null) { return new String[0]; } ArrayList<String> types = new ArrayList<String>(); int current = 0; int begin = 0; int state = 0; while (current < sqlType.length()) { switch (state) { case 0: if (sqlType.charAt(current) == ' ') { types.add(sqlType.substring(begin, current)); begin = current + 1; } else if (sqlType.charAt(current) == '[') { state = 1; } break; case 1: if (sqlType.charAt(current) == ']') { state = 0; } break; default: break; } current++; } types.add(sqlType.substring(begin, current)); String[] result = new String[types.size()]; return types.toArray(result); }
protected FieldDescriptorImpl createFieldDesc(final Class javaClass, final FieldMapping fieldMap) throws MappingException { // If not an SQL field, return a stock field descriptor. Sql sql = fieldMap.getSql(); if (sql == null) { return super.createFieldDesc(javaClass, fieldMap); } String fieldName = fieldMap.getName(); // If the field type is supplied, grab it and use it to locate the // field/accessor. Class fieldType = null; if (fieldMap.getType() != null) { fieldType = resolveType(fieldMap.getType()); } // If the field is declared as a collection, grab the collection type as // well and use it to locate the field/accessor. CollectionHandler colHandler = null; boolean isLazy = fieldMap.getLazy(); if (fieldMap.getCollection() != null) { Class colType = CollectionHandlers.getCollectionType(fieldMap.getCollection().toString()); colHandler = CollectionHandlers.getHandler(colType); if (colType.getName().equals("java.util.Iterator") && isLazy) { String err = "Lazy loading not supported for collection type 'iterator'"; throw new MappingException(err); } if (colType.getName().equals("java.util.Enumeration") && isLazy) { String err = "Lazy loading not supported for collection type 'enumerate'"; throw new MappingException(err); } } TypeInfo typeInfo = getTypeInfo(fieldType, colHandler, fieldMap); ExtendedFieldHandler exfHandler = null; FieldHandler handler = null; // -- check for user supplied FieldHandler if (fieldMap.getHandler() != null) { Class handlerClass = resolveType(fieldMap.getHandler()); if (!FieldHandler.class.isAssignableFrom(handlerClass)) { String err = "The class '" + fieldMap.getHandler() + "' must implement " + FieldHandler.class.getName(); throw new MappingException(err); } // -- get default constructor to invoke. We can't use the // -- newInstance method unfortunately becaue FieldHandler // -- overloads this method Constructor constructor = null; try { constructor = handlerClass.getConstructor(new Class[0]); handler = (FieldHandler) constructor.newInstance(new Object[0]); } catch (Exception except) { String err = "The class '" + handlerClass.getName() + "' must have a default public constructor."; throw new MappingException(err); } // -- ExtendedFieldHandler? if (handler instanceof ExtendedFieldHandler) { exfHandler = (ExtendedFieldHandler) handler; } // -- Fix for Castor JDO from Steve Vaughan, Castor JDO // -- requires FieldHandlerImpl or a ClassCastException // -- will be thrown... [KV 20030131 - also make sure this new handler // -- doesn't use it's own CollectionHandler otherwise // -- it'll cause unwanted calls to the getValue method during // -- unmarshalling] colHandler = typeInfo.getCollectionHandler(); typeInfo.setCollectionHandler(null); handler = new FieldHandlerImpl(handler, typeInfo); typeInfo.setCollectionHandler(colHandler); // -- End Castor JDO fix } boolean generalized = (exfHandler instanceof GeneralizedFieldHandler); // -- if generalized we need to change the fieldType to whatever // -- is specified in the GeneralizedFieldHandler so that the // -- correct getter/setter methods can be found FieldHandler custom = handler; if (generalized) { fieldType = ((GeneralizedFieldHandler) exfHandler).getFieldType(); } if (generalized || (handler == null)) { // -- create TypeInfoRef to get new TypeInfo from call // -- to createFieldHandler TypeInfoReference typeInfoRef = new TypeInfoReference(); typeInfoRef.typeInfo = typeInfo; handler = createFieldHandler(javaClass, fieldType, fieldMap, typeInfoRef); if (custom != null) { ((GeneralizedFieldHandler) exfHandler).setFieldHandler(handler); handler = custom; } else { typeInfo = typeInfoRef.typeInfo; } } String[] sqlName = sql.getName(); String[] sqlTypes = getSqlTypes(fieldMap); int[] sqlTypeNum; if (sqlTypes.length > 0) { sqlTypeNum = new int[sqlTypes.length]; for (int i = 0; i < sqlTypes.length; i++) { String sqlTypeString = definition2type(sqlTypes[i]); Class sqlType = SQLTypeInfos.sqlTypeName2javaType(sqlTypeString); if (_factory != null) { sqlType = _factory.adjustSqlType(sqlType); } sqlTypeNum[i] = SQLTypeInfos.javaType2sqlTypeNum(sqlType); } } else { Class sqlType = typeInfo.getFieldType(); if (_factory != null) { sqlType = _factory.adjustSqlType(sqlType); } sqlTypeNum = new int[] {SQLTypeInfos.javaType2sqlTypeNum(sqlType)}; } // create FieldDescriptor(Impl) instance, and apply JDO nature FieldDescriptorImpl fieldDescriptor = new FieldDescriptorImpl(fieldName, typeInfo, handler, fieldMap.getTransient()); fieldDescriptor.addNature(FieldDescriptorJDONature.class.getName()); fieldDescriptor.setRequired(fieldMap.getRequired()); // If we're using an ExtendedFieldHandler we need to set the FieldDescriptor if (exfHandler != null) { ((FieldHandlerFriend) exfHandler).setFieldDescriptor(fieldDescriptor); } // if SQL mapping declares transient // TODO: cross-check that this should be implemented like this if (sql.getTransient()) { fieldDescriptor.setTransient(true); } // set collection type as specified in mapping file fieldDescriptor.setCollection(fieldMap.getCollection()); fieldDescriptor.setComparator(fieldMap.getComparator()); fieldDescriptor.setCreateMethod(fieldMap.getCreateMethod()); fieldDescriptor.setGetMethod(fieldMap.getGetMethod()); fieldDescriptor.setSetMethod(fieldMap.getSetMethod()); fieldDescriptor.setDirect(fieldMap.getDirect()); // extract values for 'laziness' from field mapping fieldDescriptor.setLazy(isLazy); FieldDescriptorJDONature fieldJdoNature = new FieldDescriptorJDONature(fieldDescriptor); fieldJdoNature.setTypeConvertor(typeInfo.getConvertorFrom()); if (sqlName.length > 0) { fieldJdoNature.setSQLName(sqlName); } fieldJdoNature.setSQLType(sqlTypeNum); fieldJdoNature.setManyTable(sql.getManyTable()); if (sql.getManyKey().length > 0) { fieldJdoNature.setManyKey(sql.getManyKey()); } fieldJdoNature.setDirtyCheck(!SqlDirtyType.IGNORE.equals(sql.getDirty())); fieldJdoNature.setReadOnly(sql.getReadOnly()); fieldJdoNature.setCascading(sql.getCascading()); fieldJdoNature.setTransient(sql.getTransient()); return fieldDescriptor; }
protected TypeInfo getTypeInfo( final Class fieldType, final CollectionHandler colHandler, final FieldMapping fieldMap) throws MappingException { Class internalFieldType = Types.typeFromPrimitive(fieldType); String typeName = null; Class sqlType = null; String sqlParam = null; String[] sqlTypes = getSqlTypes(fieldMap); if ((fieldMap.getSql() != null) && (sqlTypes.length > 0)) { // --TO Check typeName = sqlTypes[0]; sqlType = SQLTypeInfos.sqlTypeName2javaType(definition2type(typeName)); sqlParam = definition2param(typeName); } else { sqlType = internalFieldType; } if (_factory != null) { sqlType = _factory.adjustSqlType(sqlType); } TypeConvertor convertorTo = null; TypeConvertor convertorFrom = null; if (internalFieldType != sqlType) { try { convertorTo = _typeConvertorRegistry.getConvertor(sqlType, internalFieldType, sqlParam); } catch (MappingException ex) { boolean isTypeSafeEnum = false; // -- check for type-safe enum style classes if ((internalFieldType != null) && (!isPrimitive(internalFieldType))) { // -- make sure no default constructor Constructor cons = null; try { cons = internalFieldType.getConstructor(EMPTY_ARGS); if (!Modifier.isPublic(cons.getModifiers())) { cons = null; } } catch (NoSuchMethodException nsmx) { // -- Do nothing } if (cons == null) { // -- make sure a valueOf factory method exists try { Method method = internalFieldType.getMethod(VALUE_OF, STRING_ARG); Class returnType = method.getReturnType(); if ((returnType != null) && internalFieldType.isAssignableFrom(returnType)) { int mods = method.getModifiers(); if (Modifier.isStatic(mods)) { // create individual SQLTypeConverter convertorTo = new String2EnumTypeConvertor(sqlType, internalFieldType, method); Types.addEnumType(internalFieldType); isTypeSafeEnum = true; } } } catch (NoSuchMethodException nsmx) { // -- Do nothing } } if (isTypeSafeEnum) { // -- check if name() method should be used instead of toString() try { Method method = internalFieldType.getMethod(NAME); if (String.class == method.getReturnType()) { convertorFrom = new Enum2StringTypeConvertor(internalFieldType, sqlType, method); } } catch (NoSuchMethodException nsmx) { // -- Do nothing } } } if (!isTypeSafeEnum) { throw new MappingException( "mapping.noConvertor", sqlType.getName(), internalFieldType.getName()); } } if (convertorFrom == null) { convertorFrom = _typeConvertorRegistry.getConvertor(internalFieldType, sqlType, sqlParam); } if ((convertorTo != null) && (convertorFrom != null)) { Types.addConvertibleType(internalFieldType); } } return new TypeInfo( internalFieldType, convertorTo, convertorFrom, fieldMap.getRequired(), null, colHandler); }