summaryrefslogtreecommitdiff
path: root/vendor/github.com/emicklei/go-restful-swagger12/model_builder.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/emicklei/go-restful-swagger12/model_builder.go')
-rw-r--r--vendor/github.com/emicklei/go-restful-swagger12/model_builder.go467
1 files changed, 0 insertions, 467 deletions
diff --git a/vendor/github.com/emicklei/go-restful-swagger12/model_builder.go b/vendor/github.com/emicklei/go-restful-swagger12/model_builder.go
deleted file mode 100644
index d40786f25..000000000
--- a/vendor/github.com/emicklei/go-restful-swagger12/model_builder.go
+++ /dev/null
@@ -1,467 +0,0 @@
-package swagger
-
-import (
- "encoding/json"
- "reflect"
- "strings"
-)
-
-// ModelBuildable is used for extending Structs that need more control over
-// how the Model appears in the Swagger api declaration.
-type ModelBuildable interface {
- PostBuildModel(m *Model) *Model
-}
-
-type modelBuilder struct {
- Models *ModelList
- Config *Config
-}
-
-type documentable interface {
- SwaggerDoc() map[string]string
-}
-
-// Check if this structure has a method with signature func (<theModel>) SwaggerDoc() map[string]string
-// If it exists, retrive the documentation and overwrite all struct tag descriptions
-func getDocFromMethodSwaggerDoc2(model reflect.Type) map[string]string {
- if docable, ok := reflect.New(model).Elem().Interface().(documentable); ok {
- return docable.SwaggerDoc()
- }
- return make(map[string]string)
-}
-
-// addModelFrom creates and adds a Model to the builder and detects and calls
-// the post build hook for customizations
-func (b modelBuilder) addModelFrom(sample interface{}) {
- if modelOrNil := b.addModel(reflect.TypeOf(sample), ""); modelOrNil != nil {
- // allow customizations
- if buildable, ok := sample.(ModelBuildable); ok {
- modelOrNil = buildable.PostBuildModel(modelOrNil)
- b.Models.Put(modelOrNil.Id, *modelOrNil)
- }
- }
-}
-
-func (b modelBuilder) addModel(st reflect.Type, nameOverride string) *Model {
- // Turn pointers into simpler types so further checks are
- // correct.
- if st.Kind() == reflect.Ptr {
- st = st.Elem()
- }
-
- modelName := b.keyFrom(st)
- if nameOverride != "" {
- modelName = nameOverride
- }
- // no models needed for primitive types
- if b.isPrimitiveType(modelName) {
- return nil
- }
- // golang encoding/json packages says array and slice values encode as
- // JSON arrays, except that []byte encodes as a base64-encoded string.
- // If we see a []byte here, treat it at as a primitive type (string)
- // and deal with it in buildArrayTypeProperty.
- if (st.Kind() == reflect.Slice || st.Kind() == reflect.Array) &&
- st.Elem().Kind() == reflect.Uint8 {
- return nil
- }
- // see if we already have visited this model
- if _, ok := b.Models.At(modelName); ok {
- return nil
- }
- sm := Model{
- Id: modelName,
- Required: []string{},
- Properties: ModelPropertyList{}}
-
- // reference the model before further initializing (enables recursive structs)
- b.Models.Put(modelName, sm)
-
- // check for slice or array
- if st.Kind() == reflect.Slice || st.Kind() == reflect.Array {
- b.addModel(st.Elem(), "")
- return &sm
- }
- // check for structure or primitive type
- if st.Kind() != reflect.Struct {
- return &sm
- }
-
- fullDoc := getDocFromMethodSwaggerDoc2(st)
- modelDescriptions := []string{}
-
- for i := 0; i < st.NumField(); i++ {
- field := st.Field(i)
- jsonName, modelDescription, prop := b.buildProperty(field, &sm, modelName)
- if len(modelDescription) > 0 {
- modelDescriptions = append(modelDescriptions, modelDescription)
- }
-
- // add if not omitted
- if len(jsonName) != 0 {
- // update description
- if fieldDoc, ok := fullDoc[jsonName]; ok {
- prop.Description = fieldDoc
- }
- // update Required
- if b.isPropertyRequired(field) {
- sm.Required = append(sm.Required, jsonName)
- }
- sm.Properties.Put(jsonName, prop)
- }
- }
-
- // We always overwrite documentation if SwaggerDoc method exists
- // "" is special for documenting the struct itself
- if modelDoc, ok := fullDoc[""]; ok {
- sm.Description = modelDoc
- } else if len(modelDescriptions) != 0 {
- sm.Description = strings.Join(modelDescriptions, "\n")
- }
-
- // update model builder with completed model
- b.Models.Put(modelName, sm)
-
- return &sm
-}
-
-func (b modelBuilder) isPropertyRequired(field reflect.StructField) bool {
- required := true
- if jsonTag := field.Tag.Get("json"); jsonTag != "" {
- s := strings.Split(jsonTag, ",")
- if len(s) > 1 && s[1] == "omitempty" {
- return false
- }
- }
- return required
-}
-
-func (b modelBuilder) buildProperty(field reflect.StructField, model *Model, modelName string) (jsonName, modelDescription string, prop ModelProperty) {
- jsonName = b.jsonNameOfField(field)
- if len(jsonName) == 0 {
- // empty name signals skip property
- return "", "", prop
- }
-
- if field.Name == "XMLName" && field.Type.String() == "xml.Name" {
- // property is metadata for the xml.Name attribute, can be skipped
- return "", "", prop
- }
-
- if tag := field.Tag.Get("modelDescription"); tag != "" {
- modelDescription = tag
- }
-
- prop.setPropertyMetadata(field)
- if prop.Type != nil {
- return jsonName, modelDescription, prop
- }
- fieldType := field.Type
-
- // check if type is doing its own marshalling
- marshalerType := reflect.TypeOf((*json.Marshaler)(nil)).Elem()
- if fieldType.Implements(marshalerType) {
- var pType = "string"
- if prop.Type == nil {
- prop.Type = &pType
- }
- if prop.Format == "" {
- prop.Format = b.jsonSchemaFormat(b.keyFrom(fieldType))
- }
- return jsonName, modelDescription, prop
- }
-
- // check if annotation says it is a string
- if jsonTag := field.Tag.Get("json"); jsonTag != "" {
- s := strings.Split(jsonTag, ",")
- if len(s) > 1 && s[1] == "string" {
- stringt := "string"
- prop.Type = &stringt
- return jsonName, modelDescription, prop
- }
- }
-
- fieldKind := fieldType.Kind()
- switch {
- case fieldKind == reflect.Struct:
- jsonName, prop := b.buildStructTypeProperty(field, jsonName, model)
- return jsonName, modelDescription, prop
- case fieldKind == reflect.Slice || fieldKind == reflect.Array:
- jsonName, prop := b.buildArrayTypeProperty(field, jsonName, modelName)
- return jsonName, modelDescription, prop
- case fieldKind == reflect.Ptr:
- jsonName, prop := b.buildPointerTypeProperty(field, jsonName, modelName)
- return jsonName, modelDescription, prop
- case fieldKind == reflect.String:
- stringt := "string"
- prop.Type = &stringt
- return jsonName, modelDescription, prop
- case fieldKind == reflect.Map:
- // if it's a map, it's unstructured, and swagger 1.2 can't handle it
- objectType := "object"
- prop.Type = &objectType
- return jsonName, modelDescription, prop
- }
-
- fieldTypeName := b.keyFrom(fieldType)
- if b.isPrimitiveType(fieldTypeName) {
- mapped := b.jsonSchemaType(fieldTypeName)
- prop.Type = &mapped
- prop.Format = b.jsonSchemaFormat(fieldTypeName)
- return jsonName, modelDescription, prop
- }
- modelType := b.keyFrom(fieldType)
- prop.Ref = &modelType
-
- if fieldType.Name() == "" { // override type of anonymous structs
- nestedTypeName := modelName + "." + jsonName
- prop.Ref = &nestedTypeName
- b.addModel(fieldType, nestedTypeName)
- }
- return jsonName, modelDescription, prop
-}
-
-func hasNamedJSONTag(field reflect.StructField) bool {
- parts := strings.Split(field.Tag.Get("json"), ",")
- if len(parts) == 0 {
- return false
- }
- for _, s := range parts[1:] {
- if s == "inline" {
- return false
- }
- }
- return len(parts[0]) > 0
-}
-
-func (b modelBuilder) buildStructTypeProperty(field reflect.StructField, jsonName string, model *Model) (nameJson string, prop ModelProperty) {
- prop.setPropertyMetadata(field)
- // Check for type override in tag
- if prop.Type != nil {
- return jsonName, prop
- }
- fieldType := field.Type
- // check for anonymous
- if len(fieldType.Name()) == 0 {
- // anonymous
- anonType := model.Id + "." + jsonName
- b.addModel(fieldType, anonType)
- prop.Ref = &anonType
- return jsonName, prop
- }
-
- if field.Name == fieldType.Name() && field.Anonymous && !hasNamedJSONTag(field) {
- // embedded struct
- sub := modelBuilder{new(ModelList), b.Config}
- sub.addModel(fieldType, "")
- subKey := sub.keyFrom(fieldType)
- // merge properties from sub
- subModel, _ := sub.Models.At(subKey)
- subModel.Properties.Do(func(k string, v ModelProperty) {
- model.Properties.Put(k, v)
- // if subModel says this property is required then include it
- required := false
- for _, each := range subModel.Required {
- if k == each {
- required = true
- break
- }
- }
- if required {
- model.Required = append(model.Required, k)
- }
- })
- // add all new referenced models
- sub.Models.Do(func(key string, sub Model) {
- if key != subKey {
- if _, ok := b.Models.At(key); !ok {
- b.Models.Put(key, sub)
- }
- }
- })
- // empty name signals skip property
- return "", prop
- }
- // simple struct
- b.addModel(fieldType, "")
- var pType = b.keyFrom(fieldType)
- prop.Ref = &pType
- return jsonName, prop
-}
-
-func (b modelBuilder) buildArrayTypeProperty(field reflect.StructField, jsonName, modelName string) (nameJson string, prop ModelProperty) {
- // check for type override in tags
- prop.setPropertyMetadata(field)
- if prop.Type != nil {
- return jsonName, prop
- }
- fieldType := field.Type
- if fieldType.Elem().Kind() == reflect.Uint8 {
- stringt := "string"
- prop.Type = &stringt
- return jsonName, prop
- }
- var pType = "array"
- prop.Type = &pType
- isPrimitive := b.isPrimitiveType(fieldType.Elem().Name())
- elemTypeName := b.getElementTypeName(modelName, jsonName, fieldType.Elem())
- prop.Items = new(Item)
- if isPrimitive {
- mapped := b.jsonSchemaType(elemTypeName)
- prop.Items.Type = &mapped
- } else {
- prop.Items.Ref = &elemTypeName
- }
- // add|overwrite model for element type
- if fieldType.Elem().Kind() == reflect.Ptr {
- fieldType = fieldType.Elem()
- }
- if !isPrimitive {
- b.addModel(fieldType.Elem(), elemTypeName)
- }
- return jsonName, prop
-}
-
-func (b modelBuilder) buildPointerTypeProperty(field reflect.StructField, jsonName, modelName string) (nameJson string, prop ModelProperty) {
- prop.setPropertyMetadata(field)
- // Check for type override in tags
- if prop.Type != nil {
- return jsonName, prop
- }
- fieldType := field.Type
-
- // override type of pointer to list-likes
- if fieldType.Elem().Kind() == reflect.Slice || fieldType.Elem().Kind() == reflect.Array {
- var pType = "array"
- prop.Type = &pType
- isPrimitive := b.isPrimitiveType(fieldType.Elem().Elem().Name())
- elemName := b.getElementTypeName(modelName, jsonName, fieldType.Elem().Elem())
- if isPrimitive {
- primName := b.jsonSchemaType(elemName)
- prop.Items = &Item{Ref: &primName}
- } else {
- prop.Items = &Item{Ref: &elemName}
- }
- if !isPrimitive {
- // add|overwrite model for element type
- b.addModel(fieldType.Elem().Elem(), elemName)
- }
- } else {
- // non-array, pointer type
- fieldTypeName := b.keyFrom(fieldType.Elem())
- var pType = b.jsonSchemaType(fieldTypeName) // no star, include pkg path
- if b.isPrimitiveType(fieldTypeName) {
- prop.Type = &pType
- prop.Format = b.jsonSchemaFormat(fieldTypeName)
- return jsonName, prop
- }
- prop.Ref = &pType
- elemName := ""
- if fieldType.Elem().Name() == "" {
- elemName = modelName + "." + jsonName
- prop.Ref = &elemName
- }
- b.addModel(fieldType.Elem(), elemName)
- }
- return jsonName, prop
-}
-
-func (b modelBuilder) getElementTypeName(modelName, jsonName string, t reflect.Type) string {
- if t.Kind() == reflect.Ptr {
- t = t.Elem()
- }
- if t.Name() == "" {
- return modelName + "." + jsonName
- }
- return b.keyFrom(t)
-}
-
-func (b modelBuilder) keyFrom(st reflect.Type) string {
- key := st.String()
- if b.Config != nil && b.Config.ModelTypeNameHandler != nil {
- if name, ok := b.Config.ModelTypeNameHandler(st); ok {
- key = name
- }
- }
- if len(st.Name()) == 0 { // unnamed type
- // Swagger UI has special meaning for [
- key = strings.Replace(key, "[]", "||", -1)
- }
- return key
-}
-
-// see also https://golang.org/ref/spec#Numeric_types
-func (b modelBuilder) isPrimitiveType(modelName string) bool {
- if len(modelName) == 0 {
- return false
- }
- return strings.Contains("uint uint8 uint16 uint32 uint64 int int8 int16 int32 int64 float32 float64 bool string byte rune time.Time", modelName)
-}
-
-// jsonNameOfField returns the name of the field as it should appear in JSON format
-// An empty string indicates that this field is not part of the JSON representation
-func (b modelBuilder) jsonNameOfField(field reflect.StructField) string {
- if jsonTag := field.Tag.Get("json"); jsonTag != "" {
- s := strings.Split(jsonTag, ",")
- if s[0] == "-" {
- // empty name signals skip property
- return ""
- } else if s[0] != "" {
- return s[0]
- }
- }
- return field.Name
-}
-
-// see also http://json-schema.org/latest/json-schema-core.html#anchor8
-func (b modelBuilder) jsonSchemaType(modelName string) string {
- schemaMap := map[string]string{
- "uint": "integer",
- "uint8": "integer",
- "uint16": "integer",
- "uint32": "integer",
- "uint64": "integer",
-
- "int": "integer",
- "int8": "integer",
- "int16": "integer",
- "int32": "integer",
- "int64": "integer",
-
- "byte": "integer",
- "float64": "number",
- "float32": "number",
- "bool": "boolean",
- "time.Time": "string",
- }
- mapped, ok := schemaMap[modelName]
- if !ok {
- return modelName // use as is (custom or struct)
- }
- return mapped
-}
-
-func (b modelBuilder) jsonSchemaFormat(modelName string) string {
- if b.Config != nil && b.Config.SchemaFormatHandler != nil {
- if mapped := b.Config.SchemaFormatHandler(modelName); mapped != "" {
- return mapped
- }
- }
- schemaMap := map[string]string{
- "int": "int32",
- "int32": "int32",
- "int64": "int64",
- "byte": "byte",
- "uint": "integer",
- "uint8": "byte",
- "float64": "double",
- "float32": "float",
- "time.Time": "date-time",
- "*time.Time": "date-time",
- }
- mapped, ok := schemaMap[modelName]
- if !ok {
- return "" // no format
- }
- return mapped
-}