protected Schema createSchema()

in lang/java/avro/src/main/java/org/apache/avro/reflect/ReflectData.java [617:776]


  protected Schema createSchema(Type type, Map<String, Schema> names) {
    if (type instanceof GenericArrayType) { // generic array
      Type component = ((GenericArrayType) type).getGenericComponentType();
      if (component == Byte.TYPE) // byte array
        return Schema.create(Schema.Type.BYTES);
      Schema result = Schema.createArray(createSchema(component, names));
      setElement(result, component);
      return result;
    } else if (type instanceof ParameterizedType) {
      ParameterizedType ptype = (ParameterizedType) type;
      Class raw = (Class) ptype.getRawType();
      Type[] params = ptype.getActualTypeArguments();
      if (Map.class.isAssignableFrom(raw)) { // Map
        Class key = (Class) params[0];
        if (isStringable(key)) { // Stringable key
          Schema schema = Schema.createMap(createSchema(params[1], names));
          schema.addProp(KEY_CLASS_PROP, key.getName());
          return schema;
        } else if (key != String.class) {
          Schema schema = createNonStringMapSchema(params[0], params[1], names);
          schema.addProp(CLASS_PROP, raw.getName());
          return schema;
        }
      } else if (Collection.class.isAssignableFrom(raw)) { // Collection
        if (params.length != 1)
          throw new AvroTypeException("No array type specified.");
        Schema schema = Schema.createArray(createSchema(params[0], names));
        schema.addProp(CLASS_PROP, raw.getName());
        return schema;
      }
    } else if ((type == Byte.class) || (type == Byte.TYPE)) {
      Schema result = Schema.create(Schema.Type.INT);
      result.addProp(CLASS_PROP, Byte.class.getName());
      return result;
    } else if ((type == Short.class) || (type == Short.TYPE)) {
      Schema result = Schema.create(Schema.Type.INT);
      result.addProp(CLASS_PROP, Short.class.getName());
      return result;
    } else if ((type == Character.class) || (type == Character.TYPE)) {
      Schema result = Schema.create(Schema.Type.INT);
      result.addProp(CLASS_PROP, Character.class.getName());
      return result;
    } else if (type instanceof Class) { // Class
      Class<?> c = (Class<?>) type;
      while (c.isAnonymousClass()) {
        c = c.getSuperclass();
      }
      if (c.isPrimitive() || // primitives
          c == Void.class || c == Boolean.class || c == Integer.class || c == Long.class || c == Float.class
          || c == Double.class || c == Byte.class || c == Short.class || c == Character.class)
        return super.createSchema(type, names);
      if (c.isArray()) { // array
        Class component = c.getComponentType();
        if (component == Byte.TYPE) { // byte array
          Schema result = Schema.create(Schema.Type.BYTES);
          result.addProp(CLASS_PROP, c.getName());
          return result;
        }
        Schema result = Schema.createArray(createSchema(component, names));
        result.addProp(CLASS_PROP, c.getName());
        setElement(result, component);
        return result;
      }
      AvroSchema explicit = c.getAnnotation(AvroSchema.class);
      if (explicit != null) // explicit schema
        return new Schema.Parser().parse(explicit.value());
      if (CharSequence.class.isAssignableFrom(c)) // String
        return Schema.create(Schema.Type.STRING);
      if (ByteBuffer.class.isAssignableFrom(c)) // bytes
        return Schema.create(Schema.Type.BYTES);
      if (Collection.class.isAssignableFrom(c)) // array
        throw new AvroRuntimeException("Can't find element type of Collection");
      Conversion<?> conversion = getConversionByClass(c);
      if (conversion != null) {
        return conversion.getRecommendedSchema();
      }
      String fullName = c.getName();
      Schema schema = names.get(fullName);
      if (schema == null) {
        AvroDoc annotatedDoc = c.getAnnotation(AvroDoc.class); // Docstring
        String doc = (annotatedDoc != null) ? annotatedDoc.value() : null;
        String name = c.getSimpleName();
        String space = c.getPackage() == null ? "" : c.getPackage().getName();
        if (c.getEnclosingClass() != null) // nested class
          space = c.getEnclosingClass().getName().replace('$', '.');
        Union union = c.getAnnotation(Union.class);
        if (union != null) { // union annotated
          return getAnnotatedUnion(union, names);
        } else if (isStringable(c)) { // Stringable
          Schema result = Schema.create(Schema.Type.STRING);
          result.addProp(CLASS_PROP, c.getName());
          return result;
        } else if (c.isEnum()) { // Enum
          List<String> symbols = new ArrayList<>();
          Enum[] constants = (Enum[]) c.getEnumConstants();
          for (Enum constant : constants)
            symbols.add(constant.name());
          schema = Schema.createEnum(name, doc, space, symbols);
          consumeAvroAliasAnnotation(c, schema);
        } else if (GenericFixed.class.isAssignableFrom(c)) { // fixed
          int size = c.getAnnotation(FixedSize.class).value();
          schema = Schema.createFixed(name, doc, space, size);
          consumeAvroAliasAnnotation(c, schema);
        } else if (IndexedRecord.class.isAssignableFrom(c)) { // specific
          return super.createSchema(type, names);
        } else { // record
          List<Schema.Field> fields = new ArrayList<>();
          boolean error = Throwable.class.isAssignableFrom(c);
          schema = Schema.createRecord(name, doc, space, error);
          consumeAvroAliasAnnotation(c, schema);
          names.put(c.getName(), schema);
          for (Field field : getCachedFields(c))
            if ((field.getModifiers() & (Modifier.TRANSIENT | Modifier.STATIC)) == 0
                && !field.isAnnotationPresent(AvroIgnore.class)) {
              Schema fieldSchema = createFieldSchema(field, names);
              annotatedDoc = field.getAnnotation(AvroDoc.class); // Docstring
              doc = (annotatedDoc != null) ? annotatedDoc.value() : null;

              Object defaultValue = createSchemaDefaultValue(type, field, fieldSchema);

              AvroName annotatedName = field.getAnnotation(AvroName.class); // Rename fields
              String fieldName = (annotatedName != null) ? annotatedName.value() : field.getName();
              if (STRING_OUTER_PARENT_REFERENCE.equals(fieldName)) {
                throw new AvroTypeException("Class " + fullName + " must be a static inner class");
              }
              Schema.Field recordField = new Schema.Field(fieldName, fieldSchema, doc, defaultValue);

              AvroMeta[] metadata = field.getAnnotationsByType(AvroMeta.class); // add metadata
              for (AvroMeta meta : metadata) {
                if (recordField.propsContainsKey(meta.key())) {
                  throw new AvroTypeException("Duplicate field prop key: " + meta.key());
                }
                recordField.addProp(meta.key(), meta.value());
              }
              for (Schema.Field f : fields) {
                if (f.name().equals(fieldName))
                  throw new AvroTypeException("double field entry: " + fieldName);
              }

              consumeFieldAlias(field, recordField);

              fields.add(recordField);
            }
          if (error) // add Throwable message
            fields.add(new Schema.Field("detailMessage", THROWABLE_MESSAGE, null, null));
          schema.setFields(fields);
          AvroMeta[] metadata = c.getAnnotationsByType(AvroMeta.class);
          for (AvroMeta meta : metadata) {
            if (schema.propsContainsKey(meta.key())) {
              throw new AvroTypeException("Duplicate type prop key: " + meta.key());
            }
            schema.addProp(meta.key(), meta.value());
          }
        }
        names.put(fullName, schema);
      }
      return schema;
    }
    return super.createSchema(type, names);
  }