Repository: deepmap/oapi-codegen
Pull request #601 (2022-05-31 08:53:48)

Generate type names in GoDoc comments

To make sure that our commented types appear as "official" GoDoc
comments, we need to prefix each

To avoid duplicating too much code, we can create an overloaded
`StringWithTypeNameToGoComment` which delegates to a shared
`stringToGoCommentWithPrefix`.

We then need to move this execution into the template, as we do not have
access to the `TypeName` at the point prior that we're attempting to
generate our comments.

This also includes the fields that are generated inside structs.

This includes any `make generate` changes, too.



deepmap-marcinr: I would prefer that people write Go-style descriptions in the OpenAPI spec. While this makes linters happy, I think it makes the comments in the code less readable. I intentionally don't mess with these things in the code generator - trying to pass through as much stuff unedited as possible. Someone who cares can fix their spec.
jamietanna: Hmm, that works when we're in control of the OpenAPI but when ie using something like Petstore, or a vendor OpenAPI there's no chance for us to update it to make it match the Go-style comment by prefixing the type, and that's trivial for us.

Out of interest why do you see this as less readable?

Patch:
diff --git a/README.md b/README.md
index 07224f8..3eadd00 100644
--- a/README.md
+++ b/README.md
@@ -361,8 +361,8 @@ look through those tests for more usage examples.
 
 #### oneOf/anyOf/allOf support
 
-- `oneOf` and `anyOf` are implemented using delayed parsing with the help of `json.RawMessage`. 
-The following schema will result in a type that has methods such as `AsCat`, `AsDog`, `FromCat`, `FromDog`. If the schema also includes a discriminator the generated code will also have methods such as `Discriminator`, `ValueByDiscriminator` and will force discriminator value in `From` methods.
+- `oneOf` and `anyOf` are implemented using delayed parsing with the help of `json.RawMessage`.
+The following schema will result in a type that has methods such as `AsCat`, `AsDog`, `FromCat`, `FromDog`, `MergeCat`, `MergeDog`. If the schema also includes a discriminator the generated code will also have methods such as `Discriminator`, `ValueByDiscriminator` and will force discriminator value in `From` methods.
 ```yaml
 schema:
   oneOf:
@@ -574,7 +574,59 @@ which help you to use the various OpenAPI 3 Authentication mechanism.
   ```
   Name string `json:"name" tag1:"value1" tag2:"value2"`
   ```
-  
+- `x-go-type-import`: adds extra Go imports to your generated code. It can help you, when you want to
+   choose your own import package for `x-go-type`.
+
+  ```yaml
+    schemas:
+      Pet:
+        properties:
+          age:
+            x-go-type: myuuid.UUID
+            x-go-type-import:
+              name: myuuid
+              path: github.com/google/uuid
+  ```
+  After code generation you will get this:
+  ```go
+    import (
+        ...
+        myuuid "github.com/google/uuid"
+    )
+    
+  //Pet defines model for Pet.
+    type Pet struct {
+        Age *myuuid.UUID `json:"age,omitempty"`
+    }
+
+  ```
+  `name` is an optional parameter. Example:
+
+  ```yaml
+  components:
+  schemas:
+    Pet:
+      properties:
+        age:
+          x-go-type: uuid.UUID
+          x-go-type-import:
+            path: github.com/google/uuid
+      required:
+        - age
+  ```
+
+  After code generation you will get this result:
+
+  ```go
+  import (
+	  "github.com/google/uuid"
+  )
+
+  // Pet defines model for Pet.
+  type Pet struct {
+	  Age uuid.UUID `json:"age"`
+  }
+  ```
 
 
 ## Using `oapi-codegen`
@@ -626,15 +678,18 @@ file via the `--config` option. Please see the test under
 for an example. The structure of the file is as follows:
     
 ```yaml
-output:
-  externalref.gen.go
 package: externalref
 generate:
-  - types
-  - skip-prune
+  models: true
+  embedded-spec: true
+output-options:
+  skip-prune: true
 import-mapping:
   ./packageA/spec.yaml: github.com/deepmap/oapi-codegen/internal/test/externalref/packageA
   ./packageB/spec.yaml: github.com/deepmap/oapi-codegen/internal/test/externalref/packageB
+output: externalref.gen.go
+output-options:
+  skip-prune: true
 ```
 
 Have a look at [`cmd/oapi-codegen/oapi-codegen.go`](https://github.com/deepmap/oapi-codegen/blob/master/cmd/oapi-codegen/oapi-codegen.go#L48) 
diff --git a/examples/authenticated-api/echo/api/api.gen.go b/examples/authenticated-api/echo/api/api.gen.go
index 14f393d..64689fd 100644
--- a/examples/authenticated-api/echo/api/api.gen.go
+++ b/examples/authenticated-api/echo/api/api.gen.go
@@ -27,10 +27,10 @@ const (
 
 // Error defines model for Error.
 type Error struct {
-	// Error code
+	// Code Error code
 	Code int32 `json:"code"`
 
-	// Error message
+	// Message Error message
 	Message string `json:"message"`
 }
 
diff --git a/examples/petstore-expanded/chi/api/petstore.gen.go b/examples/petstore-expanded/chi/api/petstore.gen.go
index 4a514dc..4234451 100644
--- a/examples/petstore-expanded/chi/api/petstore.gen.go
+++ b/examples/petstore-expanded/chi/api/petstore.gen.go
@@ -20,40 +20,40 @@ import (
 
 // Error defines model for Error.
 type Error struct {
-	// Error code
+	// Code Error code
 	Code int32 `json:"code"`
 
-	// Error message
+	// Message Error message
 	Message string `json:"message"`
 }
 
 // NewPet defines model for NewPet.
 type NewPet struct {
-	// Name of the pet
+	// Name Name of the pet
 	Name string `json:"name"`
 
-	// Type of the pet
+	// Tag Type of the pet
 	Tag *string `json:"tag,omitempty"`
 }
 
 // Pet defines model for Pet.
 type Pet struct {
-	// Unique id of the pet
+	// Id Unique id of the pet
 	Id int64 `json:"id"`
 
-	// Name of the pet
+	// Name Name of the pet
 	Name string `json:"name"`
 
-	// Type of the pet
+	// Tag Type of the pet
 	Tag *string `json:"tag,omitempty"`
 }
 
 // FindPetsParams defines parameters for FindPets.
 type FindPetsParams struct {
-	// tags to filter by
+	// Tags tags to filter by
 	Tags *[]string `form:"tags,omitempty" json:"tags,omitempty"`
 
-	// maximum number of results to return
+	// Limit maximum number of results to return
 	Limit *int32 `form:"limit,omitempty" json:"limit,omitempty"`
 }
 
@@ -95,9 +95,6 @@ func (siw *ServerInterfaceWrapper) FindPets(w http.ResponseWriter, r *http.Reque
 	var params FindPetsParams
 
 	// ------------- Optional query parameter "tags" -------------
-	if paramValue := r.URL.Query().Get("tags"); paramValue != "" {
-
-	}
 
 	err = runtime.BindQueryParameter("form", true, false, "tags", r.URL.Query(), &params.Tags)
 	if err != nil {
@@ -106,9 +103,6 @@ func (siw *ServerInterfaceWrapper) FindPets(w http.ResponseWriter, r *http.Reque
 	}
 
 	// ------------- Optional query parameter "limit" -------------
-	if paramValue := r.URL.Query().Get("limit"); paramValue != "" {
-
-	}
 
 	err = runtime.BindQueryParameter("form", true, false, "limit", r.URL.Query(), &params.Limit)
 	if err != nil {
diff --git a/examples/petstore-expanded/echo/api/models/models.gen.go b/examples/petstore-expanded/echo/api/models/models.gen.go
index 701ac37..f15f255 100644
--- a/examples/petstore-expanded/echo/api/models/models.gen.go
+++ b/examples/petstore-expanded/echo/api/models/models.gen.go
@@ -5,40 +5,40 @@ package models
 
 // Error defines model for Error.
 type Error struct {
-	// Error code
+	// Code Error code
 	Code int32 `json:"code"`
 
-	// Error message
+	// Message Error message
 	Message string `json:"message"`
 }
 
 // NewPet defines model for NewPet.
 type NewPet struct {
-	// Name of the pet
+	// Name Name of the pet
 	Name string `json:"name"`
 
-	// Type of the pet
+	// Tag Type of the pet
 	Tag *string `json:"tag,omitempty"`
 }
 
 // Pet defines model for Pet.
 type Pet struct {
-	// Unique id of the pet
+	// Id Unique id of the pet
 	Id int64 `json:"id"`
 
-	// Name of the pet
+	// Name Name of the pet
 	Name string `json:"name"`
 
-	// Type of the pet
+	// Tag Type of the pet
 	Tag *string `json:"tag,omitempty"`
 }
 
 // FindPetsParams defines parameters for FindPets.
 type FindPetsParams struct {
-	// tags to filter by
+	// Tags tags to filter by
 	Tags *[]string `form:"tags,omitempty" json:"tags,omitempty"`
 
-	// maximum number of results to return
+	// Limit maximum number of results to return
 	Limit *int32 `form:"limit,omitempty" json:"limit,omitempty"`
 }
 
diff --git a/examples/petstore-expanded/gin/api/petstore-server.gen.go b/examples/petstore-expanded/gin/api/petstore-server.gen.go
index eeba01a..09ec102 100644
--- a/examples/petstore-expanded/gin/api/petstore-server.gen.go
+++ b/examples/petstore-expanded/gin/api/petstore-server.gen.go
@@ -51,9 +51,6 @@ func (siw *ServerInterfaceWrapper) FindPets(c *gin.Context) {
 	var params FindPetsParams
 
 	// ------------- Optional query parameter "tags" -------------
-	if paramValue := c.Query("tags"); paramValue != "" {
-
-	}
 
 	err = runtime.BindQueryParameter("form", true, false, "tags", c.Request.URL.Query(), &params.Tags)
 	if err != nil {
@@ -62,9 +59,6 @@ func (siw *ServerInterfaceWrapper) FindPets(c *gin.Context) {
 	}
 
 	// ------------- Optional query parameter "limit" -------------
-	if paramValue := c.Query("limit"); paramValue != "" {
-
-	}
 
 	err = runtime.BindQueryParameter("form", true, false, "limit", c.Request.URL.Query(), &params.Limit)
 	if err != nil {
diff --git a/examples/petstore-expanded/gin/api/petstore-types.gen.go b/examples/petstore-expanded/gin/api/petstore-types.gen.go
index e3c73d1..16bbe20 100644
--- a/examples/petstore-expanded/gin/api/petstore-types.gen.go
+++ b/examples/petstore-expanded/gin/api/petstore-types.gen.go
@@ -5,40 +5,40 @@ package api
 
 // Error defines model for Error.
 type Error struct {
-	// Error code
+	// Code Error code
 	Code int32 `json:"code"`
 
-	// Error message
+	// Message Error message
 	Message string `json:"message"`
 }
 
 // NewPet defines model for NewPet.
 type NewPet struct {
-	// Name of the pet
+	// Name Name of the pet
 	Name string `json:"name"`
 
-	// Type of the pet
+	// Tag Type of the pet
 	Tag *string `json:"tag,omitempty"`
 }
 
 // Pet defines model for Pet.
 type Pet struct {
-	// Unique id of the pet
+	// Id Unique id of the pet
 	Id int64 `json:"id"`
 
-	// Name of the pet
+	// Name Name of the pet
 	Name string `json:"name"`
 
-	// Type of the pet
+	// Tag Type of the pet
 	Tag *string `json:"tag,omitempty"`
 }
 
 // FindPetsParams defines parameters for FindPets.
 type FindPetsParams struct {
-	// tags to filter by
+	// Tags tags to filter by
 	Tags *[]string `form:"tags,omitempty" json:"tags,omitempty"`
 
-	// maximum number of results to return
+	// Limit maximum number of results to return
 	Limit *int32 `form:"limit,omitempty" json:"limit,omitempty"`
 }
 
diff --git a/examples/petstore-expanded/gorilla/api/petstore.gen.go b/examples/petstore-expanded/gorilla/api/petstore.gen.go
index 5a3e901..56762c5 100644
--- a/examples/petstore-expanded/gorilla/api/petstore.gen.go
+++ b/examples/petstore-expanded/gorilla/api/petstore.gen.go
@@ -20,40 +20,40 @@ import (
 
 // Error defines model for Error.
 type Error struct {
-	// Error code
+	// Code Error code
 	Code int32 `json:"code"`
 
-	// Error message
+	// Message Error message
 	Message string `json:"message"`
 }
 
 // NewPet defines model for NewPet.
 type NewPet struct {
-	// Name of the pet
+	// Name Name of the pet
 	Name string `json:"name"`
 
-	// Type of the pet
+	// Tag Type of the pet
 	Tag *string `json:"tag,omitempty"`
 }
 
 // Pet defines model for Pet.
 type Pet struct {
-	// Unique id of the pet
+	// Id Unique id of the pet
 	Id int64 `json:"id"`
 
-	// Name of the pet
+	// Name Name of the pet
 	Name string `json:"name"`
 
-	// Type of the pet
+	// Tag Type of the pet
 	Tag *string `json:"tag,omitempty"`
 }
 
 // FindPetsParams defines parameters for FindPets.
 type FindPetsParams struct {
-	// tags to filter by
+	// Tags tags to filter by
 	Tags *[]string `form:"tags,omitempty" json:"tags,omitempty"`
 
-	// maximum number of results to return
+	// Limit maximum number of results to return
 	Limit *int32 `form:"limit,omitempty" json:"limit,omitempty"`
 }
 
@@ -95,9 +95,6 @@ func (siw *ServerInterfaceWrapper) FindPets(w http.ResponseWriter, r *http.Reque
 	var params FindPetsParams
 
 	// ------------- Optional query parameter "tags" -------------
-	if paramValue := r.URL.Query().Get("tags"); paramValue != "" {
-
-	}
 
 	err = runtime.BindQueryParameter("form", true, false, "tags", r.URL.Query(), &params.Tags)
 	if err != nil {
@@ -106,9 +103,6 @@ func (siw *ServerInterfaceWrapper) FindPets(w http.ResponseWriter, r *http.Reque
 	}
 
 	// ------------- Optional query parameter "limit" -------------
-	if paramValue := r.URL.Query().Get("limit"); paramValue != "" {
-
-	}
 
 	err = runtime.BindQueryParameter("form", true, false, "limit", r.URL.Query(), &params.Limit)
 	if err != nil {
diff --git a/examples/petstore-expanded/petstore-client.gen.go b/examples/petstore-expanded/petstore-client.gen.go
index bbd8aa2..03435d2 100644
--- a/examples/petstore-expanded/petstore-client.gen.go
+++ b/examples/petstore-expanded/petstore-client.gen.go
@@ -19,40 +19,40 @@ import (
 
 // Error defines model for Error.
 type Error struct {
-	// Error code
+	// Code Error code
 	Code int32 `json:"code"`
 
-	// Error message
+	// Message Error message
 	Message string `json:"message"`
 }
 
 // NewPet defines model for NewPet.
 type NewPet struct {
-	// Name of the pet
+	// Name Name of the pet
 	Name string `json:"name"`
 
-	// Type of the pet
+	// Tag Type of the pet
 	Tag *string `json:"tag,omitempty"`
 }
 
 // Pet defines model for Pet.
 type Pet struct {
-	// Unique id of the pet
+	// Id Unique id of the pet
 	Id int64 `json:"id"`
 
-	// Name of the pet
+	// Name Name of the pet
 	Name string `json:"name"`
 
-	// Type of the pet
+	// Tag Type of the pet
 	Tag *string `json:"tag,omitempty"`
 }
 
 // FindPetsParams defines parameters for FindPets.
 type FindPetsParams struct {
-	// tags to filter by
+	// Tags tags to filter by
 	Tags *[]string `form:"tags,omitempty" json:"tags,omitempty"`
 
-	// maximum number of results to return
+	// Limit maximum number of results to return
 	Limit *int32 `form:"limit,omitempty" json:"limit,omitempty"`
 }
 
diff --git a/examples/petstore-expanded/strict/api/petstore-server.gen.go b/examples/petstore-expanded/strict/api/petstore-server.gen.go
index 7c10ee2..b229efd 100644
--- a/examples/petstore-expanded/strict/api/petstore-server.gen.go
+++ b/examples/petstore-expanded/strict/api/petstore-server.gen.go
@@ -55,9 +55,6 @@ func (siw *ServerInterfaceWrapper) FindPets(w http.ResponseWriter, r *http.Reque
 	var params FindPetsParams
 
 	// ------------- Optional query parameter "tags" -------------
-	if paramValue := r.URL.Query().Get("tags"); paramValue != "" {
-
-	}
 
 	err = runtime.BindQueryParameter("form", true, false, "tags", r.URL.Query(), &params.Tags)
 	if err != nil {
@@ -66,9 +63,6 @@ func (siw *ServerInterfaceWrapper) FindPets(w http.ResponseWriter, r *http.Reque
 	}
 
 	// ------------- Optional query parameter "limit" -------------
-	if paramValue := r.URL.Query().Get("limit"); paramValue != "" {
-
-	}
 
 	err = runtime.BindQueryParameter("form", true, false, "limit", r.URL.Query(), &params.Limit)
 	if err != nil {
@@ -376,13 +370,30 @@ type StrictHandlerFunc func(ctx context.Context, w http.ResponseWriter, r *http.
 
 type StrictMiddlewareFunc func(f StrictHandlerFunc, operationID string) StrictHandlerFunc
 
+type StrictChiServerOptions struct {
+	RequestErrorHandlerFunc  func(w http.ResponseWriter, r *http.Request, err error)
+	ResponseErrorHandlerFunc func(w http.ResponseWriter, r *http.Request, err error)
+}
+
 func NewStrictHandler(ssi StrictServerInterface, middlewares []StrictMiddlewareFunc) ServerInterface {
-	return &strictHandler{ssi: ssi, middlewares: middlewares}
+	return &strictHandler{ssi: ssi, middlewares: middlewares, options: StrictChiServerOptions{
+		RequestErrorHandlerFunc: func(w http.ResponseWriter, r *http.Request, err error) {
+			http.Error(w, err.Error(), http.StatusBadRequest)
+		},
+		ResponseErrorHandlerFunc: func(w http.ResponseWriter, r *http.Request, err error) {
+			http.Error(w, err.Error(), http.StatusInternalServerError)
+		},
+	}}
+}
+
+func NewStrictHandlerWithOptions(ssi StrictServerInterface, middlewares []StrictMiddlewareFunc, options StrictChiServerOptions) ServerInterface {
+	return &strictHandler{ssi: ssi, middlewares: middlewares, options: options}
 }
 
 type strictHandler struct {
 	ssi         StrictServerInterface
 	middlewares []StrictMiddlewareFunc
+	options     StrictChiServerOptions
 }
 
 // FindPets operation middleware
@@ -410,10 +421,10 @@ func (sh *strictHandler) FindPets(w http.ResponseWriter, r *http.Request, params
 		w.WriteHeader(v.StatusCode)
 		writeJSON(w, v)
 	case error:
-		http.Error(w, v.Error(), http.StatusInternalServerError)
+		sh.options.ResponseErrorHandlerFunc(w, r, v)
 	case nil:
 	default:
-		http.Error(w, fmt.Sprintf("Unexpected response type: %T", v), http.StatusInternalServerError)
+		sh.options.ResponseErrorHandlerFunc(w, r, fmt.Errorf("Unexpected response type: %T", v))
 	}
 }
 
@@ -423,7 +434,7 @@ func (sh *strictHandler) AddPet(w http.ResponseWriter, r *http.Request) {
 
 	var body AddPetJSONRequestBody
 	if err := json.NewDecoder(r.Body).Decode(&body); err != nil {
-		http.Error(w, "can't decode JSON body: "+err.Error(), http.StatusBadRequest)
+		sh.options.RequestErrorHandlerFunc(w, r, fmt.Errorf("can't decode JSON body: %w", err))
 		return
 	}
 	request.Body = &body
@@ -447,10 +458,10 @@ func (sh *strictHandler) AddPet(w http.ResponseWriter, r *http.Request) {
 		w.WriteHeader(v.StatusCode)
 		writeJSON(w, v)
 	case error:
-		http.Error(w, v.Error(), http.StatusInternalServerError)
+		sh.options.ResponseErrorHandlerFunc(w, r, v)
 	case nil:
 	default:
-		http.Error(w, fmt.Sprintf("Unexpected response type: %T", v), http.StatusInternalServerError)
+		sh.options.ResponseErrorHandlerFunc(w, r, fmt.Errorf("Unexpected response type: %T", v))
 	}
 }
 
@@ -477,10 +488,10 @@ func (sh *strictHandler) DeletePet(w http.ResponseWriter, r *http.Request, id in
 		w.WriteHeader(v.StatusCode)
 		writeJSON(w, v)
 	case error:
-		http.Error(w, v.Error(), http.StatusInternalServerError)
+		sh.options.ResponseErrorHandlerFunc(w, r, v)
 	case nil:
 	default:
-		http.Error(w, fmt.Sprintf("Unexpected response type: %T", v), http.StatusInternalServerError)
+		sh.options.ResponseErrorHandlerFunc(w, r, fmt.Errorf("Unexpected response type: %T", v))
 	}
 }
 
@@ -509,10 +520,10 @@ func (sh *strictHandler) FindPetByID(w http.ResponseWriter, r *http.Request, id
 		w.WriteHeader(v.StatusCode)
 		writeJSON(w, v)
 	case error:
-		http.Error(w, v.Error(), http.StatusInternalServerError)
+		sh.options.ResponseErrorHandlerFunc(w, r, v)
 	case nil:
 	default:
-		http.Error(w, fmt.Sprintf("Unexpected response type: %T", v), http.StatusInternalServerError)
+		sh.options.ResponseErrorHandlerFunc(w, r, fmt.Errorf("Unexpected response type: %T", v))
 	}
 }
 
diff --git a/examples/petstore-expanded/strict/api/petstore-types.gen.go b/examples/petstore-expanded/strict/api/petstore-types.gen.go
index e3c73d1..16bbe20 100644
--- a/examples/petstore-expanded/strict/api/petstore-types.gen.go
+++ b/examples/petstore-expanded/strict/api/petstore-types.gen.go
@@ -5,40 +5,40 @@ package api
 
 // Error defines model for Error.
 type Error struct {
-	// Error code
+	// Code Error code
 	Code int32 `json:"code"`
 
-	// Error message
+	// Message Error message
 	Message string `json:"message"`
 }
 
 // NewPet defines model for NewPet.
 type NewPet struct {
-	// Name of the pet
+	// Name Name of the pet
 	Name string `json:"name"`
 
-	// Type of the pet
+	// Tag Type of the pet
 	Tag *string `json:"tag,omitempty"`
 }
 
 // Pet defines model for Pet.
 type Pet struct {
-	// Unique id of the pet
+	// Id Unique id of the pet
 	Id int64 `json:"id"`
 
-	// Name of the pet
+	// Name Name of the pet
 	Name string `json:"name"`
 
-	// Type of the pet
+	// Tag Type of the pet
 	Tag *string `json:"tag,omitempty"`
 }
 
 // FindPetsParams defines parameters for FindPets.
 type FindPetsParams struct {
-	// tags to filter by
+	// Tags tags to filter by
 	Tags *[]string `form:"tags,omitempty" json:"tags,omitempty"`
 
-	// maximum number of results to return
+	// Limit maximum number of results to return
 	Limit *int32 `form:"limit,omitempty" json:"limit,omitempty"`
 }
 
diff --git a/go.mod b/go.mod
index 60272ca..75775ba 100644
--- a/go.mod
+++ b/go.mod
@@ -1,6 +1,7 @@
 module github.com/deepmap/oapi-codegen
 
 require (
+	github.com/apapsch/go-jsonmerge/v2 v2.0.0
 	github.com/cyberdelia/templates v0.0.0-20141128023046-ca7fffd4298c
 	github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 // indirect
 	github.com/getkin/kin-openapi v0.94.0
diff --git a/go.sum b/go.sum
index 5329680..bc96489 100644
--- a/go.sum
+++ b/go.sum
@@ -1,3 +1,7 @@
+github.com/RaveNoX/go-jsoncommentstrip v1.0.0/go.mod h1:78ihd09MekBnJnxpICcwzCMzGrKSKYe4AqU6PDYYpjk=
+github.com/apapsch/go-jsonmerge/v2 v2.0.0 h1:axGnT1gRIfimI7gJifB699GoE/oq+F2MU7Dml6nw9rQ=
+github.com/apapsch/go-jsonmerge/v2 v2.0.0/go.mod h1:lvDnEdqiQrp0O42VQGgmlKpxL1AP2+08jFMw88y4klk=
+github.com/bmatcuk/doublestar v1.1.1/go.mod h1:UD6OnuiIn0yFxxA2le/rnRU1G4RaI4UvFv1sNto9p6w=
 github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
 github.com/cyberdelia/templates v0.0.0-20141128023046-ca7fffd4298c h1:/ovYnF02fwL0kvspmy9AuyKg1JhdTRUgPw4nUxd9oZM=
 github.com/cyberdelia/templates v0.0.0-20141128023046-ca7fffd4298c/go.mod h1:GyV+0YP4qX0UQ7r2MoYZ+AvYDp12OF5yg4q8rGnyNh4=
@@ -56,6 +60,7 @@ github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFF
 github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
 github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
 github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
+github.com/juju/gnuflag v0.0.0-20171113085948-2ce1bb71843d/go.mod h1:2PavIy+JPciBPrBUjwbNvtwB6RQlve+hkpll6QSNmOE=
 github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
 github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
 github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
@@ -113,6 +118,7 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN
 github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
 github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUAtL9R8=
 github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE=
+github.com/spkg/bom v0.0.0-20160624110644-59b7046e48ad/go.mod h1:qLr4V1qq6nMqFKkMo8ZTx3f+BZEkzsRUY10Xsm2mwU0=
 github.com/stretchr/objx v0.1.0 h1:4G4v2dO3VZwixGIRoQ5Lfboy6nUhCyYzaqnIAPPhYs4=
 github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
 github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
@@ -204,7 +210,6 @@ gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
 gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
 gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
 gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
-gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
 gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
 gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
 gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
diff --git a/pkg/codegen/codegen.go b/pkg/codegen/codegen.go
index e87a2e1..7d03752 100644
--- a/pkg/codegen/codegen.go
+++ b/pkg/codegen/codegen.go
@@ -139,6 +139,7 @@ func Generate(spec *openapi3.T, opts Configuration) (string, error) {
 	}
 
 	var typeDefinitions, constantDefinitions string
+	var xGoTypeImports map[string]goImport
 	if opts.Generate.Models {
 		typeDefinitions, err = GenerateTypeDefinitions(t, spec, ops, opts.OutputOptions.ExcludeSchemas)
 		if err != nil {
@@ -150,6 +151,10 @@ func Generate(spec *openapi3.T, opts Configuration) (string, error) {
 			return "", fmt.Errorf("error generating constants: %w", err)
 		}
 
+		xGoTypeImports, err = GetTypeDefinitionsImports(spec, opts.OutputOptions.ExcludeSchemas)
+		if err != nil {
+			return "", fmt.Errorf("error getting type definition imports: %w", err)
+		}
 	}
 
 	var echoServerOut string
@@ -228,7 +233,7 @@ func Generate(spec *openapi3.T, opts Configuration) (string, error) {
 	var buf bytes.Buffer
 	w := bufio.NewWriter(&buf)
 
-	externalImports := importMapping.GoImports()
+	externalImports := append(importMapping.GoImports(), importMap(xGoTypeImports).GoImports()...)
 	importsOut, err := GenerateImports(t, externalImports, opts.PackageName)
 	if err != nil {
 		return "", fmt.Errorf("error generating imports: %w", err)
@@ -616,9 +621,10 @@ func GenerateEnums(t *template.Template, types []TypeDefinition) (string, error)
 				wrapper = `"`
 			}
 			enums = append(enums, EnumDefinition{
-				Schema:       tp.Schema,
-				TypeName:     tp.TypeName,
-				ValueWrapper: wrapper,
+				Schema:         tp.Schema,
+				TypeName:       tp.TypeName,
+				ValueWrapper:   wrapper,
+				PrefixTypeName: globalState.options.Compatibility.AlwaysPrefixEnumValues,
 			})
 		}
 	}
@@ -635,8 +641,8 @@ func GenerateEnums(t *template.Template, types []TypeDefinition) (string, error)
 			for e1key := range e1.GetValues() {
 				_, found := e2.GetValues()[e1key]
 				if found {
-					e1.Conflicts = true
-					e2.Conflicts = true
+					e1.PrefixTypeName = true
+					e2.PrefixTypeName = true
 					enums[i] = e1
 					enums[j] = e2
 					break
@@ -652,7 +658,7 @@ func GenerateEnums(t *template.Template, types []TypeDefinition) (string, error)
 			}
 			_, found := e1.Schema.EnumValues[tp.TypeName]
 			if found {
-				e1.Conflicts = true
+				e1.PrefixTypeName = true
 				enums[i] = e1
 			}
 		}
@@ -661,7 +667,7 @@ func GenerateEnums(t *template.Template, types []TypeDefinition) (string, error)
 		// type name.
 		_, found := e1.GetValues()[e1.TypeName]
 		if found {
-			e1.Conflicts = true
+			e1.PrefixTypeName = true
 			enums[i] = e1
 		}
 	}
@@ -787,3 +793,106 @@ func LoadTemplates(src embed.FS, t *template.Template) error {
 		return nil
 	})
 }
+
+func GetTypeDefinitionsImports(swagger *openapi3.T, excludeSchemas []string) (map[string]goImport, error) {
+	res := map[string]goImport{}
+	schemaImports, err := GetSchemaImports(swagger.Components.Schemas, excludeSchemas)
+	if err != nil {
+		return nil, err
+	}
+
+	reqBodiesImports, err := GetRequestBodiesImports(swagger.Components.RequestBodies)
+	if err != nil {
+		return nil, err
+	}
+
+	responsesImports, err := GetResponsesImports(swagger.Components.Responses)
+	if err != nil {
+		return nil, err
+	}
+
+	for _, imprts := range []map[string]goImport{schemaImports, reqBodiesImports, responsesImports} {
+		for k, v := range imprts {
+			res[k] = v
+		}
+	}
+	return res, nil
+}
+
+func GetSchemaImports(schemas map[string]*openapi3.SchemaRef, excludeSchemas []string) (map[string]goImport, error) {
+	res := map[string]goImport{}
+	excludeSchemasMap := make(map[string]bool)
+	for _, schema := range excludeSchemas {
+		excludeSchemasMap[schema] = true
+	}
+	for _, schemaName := range SortedSchemaKeys(schemas) {
+		if _, ok := excludeSchemasMap[schemaName]; ok {
+			continue
+		}
+		schema := schemas[schemaName].Value
+
+		if schema == nil || schema.Properties == nil {
+			continue
+		}
+
+		imprts, err := GetImports(schema.Properties)
+		if err != nil {
+			return nil, err
+		}
+
+		for s, gi := range imprts {
+			res[s] = gi
+		}
+	}
+	return res, nil
+}
+
+func GetRequestBodiesImports(bodies map[string]*openapi3.RequestBodyRef) (map[string]goImport, error) {
+	res := map[string]goImport{}
+	for _, requestBodyName := range SortedRequestBodyKeys(bodies) {
+		requestBodyRef := bodies[requestBodyName]
+		response := requestBodyRef.Value
+		jsonBody, found := response.Content["application/json"]
+		if found {
+			schema := jsonBody.Schema
+			if schema == nil || schema.Value == nil || schema.Value.Properties == nil {
+				continue
+			}
+
+			imprts, err := GetImports(schema.Value.Properties)
+			if err != nil {
+				return nil, err
+			}
+
+			for s, gi := range imprts {
+				res[s] = gi
+			}
+		}
+	}
+	return res, nil
+}
+
+func GetResponsesImports(responses map[string]*openapi3.ResponseRef) (map[string]goImport, error) {
+	res := map[string]goImport{}
+	for _, responseName := range SortedResponsesKeys(responses) {
+		responseOrRef := responses[responseName]
+		response := responseOrRef.Value
+		jsonResponse, found := response.Content["application/json"]
+		if found {
+			schema := jsonResponse.Schema
+			if schema == nil || schema.Value == nil || schema.Value.Properties == nil {
+				continue
+			}
+
+			imprts, err := GetImports(schema.Value.Properties)
+			if err != nil {
+				return nil, err
+			}
+
+			for s, gi := range imprts {
+				res[s] = gi
+			}
+		}
+	}
+	return res, nil
+}
diff --git a/pkg/codegen/configuration.go b/pkg/codegen/configuration.go
index c8530c8..290c139 100644
--- a/pkg/codegen/configuration.go
+++ b/pkg/codegen/configuration.go
@@ -26,7 +26,7 @@ type GenerateOptions struct {
 	EchoServer    bool `yaml:"echo-server,omitempty"`    // EchoServer specifies whether to generate echo server boilerplate
 	GinServer     bool `yaml:"gin-server,omitempty"`     // GinServer specifies whether to generate gin server boilerplate
 	GorillaServer bool `yaml:"gorilla-server,omitempty"` // GorillaServer specifies whether to generate Gorilla server boilerplate
-	Strict        bool `yaml:"strict-server,omitempty"` // Strict specifies whether to generate strict server wrapper
+	Strict        bool `yaml:"strict-server,omitempty"`  // Strict specifies whether to generate strict server wrapper
 	Client        bool `yaml:"client,omitempty"`         // Client specifies whether to generate client boilerplate
 	Models        bool `yaml:"models,omitempty"`         // Models specifies whether to generate type definitions
 	EmbeddedSpec  bool `yaml:"embedded-spec,omitempty"`  // Whether to embed the swagger spec in the generated code
@@ -57,6 +57,13 @@ type CompatibilityOptions struct {
 	// When an object contains no members, and only an additionalProperties specification,
 	// it is flattened to a map. Set
 	DisableFlattenAdditionalProperties bool `yaml:"disable-flatten-additional-properties,omitempty"`
+	// When an object property is both required and readOnly the go model is generated
+	// as a pointer. Set DisableRequiredReadOnlyAsPointer to true to mark them as non pointer.
+	// Please see https://github.com/deepmap/oapi-codegen/issues/604
+	DisableRequiredReadOnlyAsPointer bool `yaml:"disable-required-readonly-as-pointer,omitempty"`
+	// When set to true, always prefix enum values with their type name instead of only
+	// when typenames would be conflicting.
+	AlwaysPrefixEnumValues bool `yaml:"always-prefix-enum-values,omitempty"`
 }
 
 // OutputOptions are used to modify the output code in some way.
diff --git a/pkg/codegen/operations.go b/pkg/codegen/operations.go
index 32c50c0..3d63f85 100644
--- a/pkg/codegen/operations.go
+++ b/pkg/codegen/operations.go
@@ -615,7 +615,8 @@ func GenerateBodyDefinitions(operationID string, bodyOrRef *openapi3.RequestBody
 	var bodyDefinitions []RequestBodyDefinition
 	var typeDefinitions []TypeDefinition
 
-	for contentType, content := range body.Content {
+	for _, contentType := range SortedContentKeys(body.Content) {
+		content := body.Content[contentType]
 		var tag string
 		var defaultBody bool
 
diff --git a/pkg/codegen/schema.go b/pkg/codegen/schema.go
index f8da94f..8552165 100644
--- a/pkg/codegen/schema.go
+++ b/pkg/codegen/schema.go
@@ -94,7 +94,9 @@ func (p Property) GoFieldName() string {
 func (p Property) GoTypeDef() string {
 	typeDef := p.Schema.TypeDecl()
 	if !p.Schema.SkipOptionalPointer &&
-		(!p.Required || p.Nullable || p.ReadOnly || p.WriteOnly) {
+		(!p.Required || p.Nullable ||
+			(p.ReadOnly && (!p.Required || !globalState.options.Compatibility.DisableRequiredReadOnlyAsPointer)) ||
+			p.WriteOnly) {
 
 		typeDef = "*" + typeDef
 	}
@@ -111,15 +113,17 @@ type EnumDefinition struct {
 	// ValueWrapper wraps the value. It's used to conditionally apply quotes
 	// around strings.
 	ValueWrapper string
-	// Conflicts is set to true when this enum conflicts with another in
-	// terms of TypeNames
-	Conflicts bool
+	// PrefixTypeName determines if the enum value is prefixed with its TypeName.
+	// This is set to true when this enum conflicts with another in terms of
+	// TypeNames or when explicitly requested via the
+	// `compatibility.always-prefix-enum-values` option.
+	PrefixTypeName bool
 }
 
 // GetValues generates enum names in a way to minimize global conflicts
 func (e *EnumDefinition) GetValues() map[string]string {
 	// in case there are no conflicts, it's safe to use the values as-is
-	if !e.Conflicts {
+	if !e.PrefixTypeName {
 		return e.Schema.EnumValues
 	}
 	// If we do have conflicts, we will prefix the enum's typename to the values.
@@ -216,13 +220,13 @@ func GenerateGoSchema(sref *openapi3.SchemaRef, path []string) (Schema, error) {
 		}
 		return Schema{
 			GoType:         refType,
-			Description:    StringToGoComment(schema.Description),
+			Description:    schema.Description,
 			DefineViaAlias: true,
 		}, nil
 	}
 
 	outSchema := Schema{
-		Description: StringToGoComment(schema.Description),
+		Description: schema.Description,
 		OAPISchema:  schema,
 	}
 
@@ -563,6 +567,14 @@ func GenFieldsFromProperties(props []Property) []string {
 	var fields []string
 	for i, p := range props {
 		field := ""
+
+		goFieldName := p.GoFieldName()
+		if _, ok := p.ExtensionProps.Extensions[extGoName]; ok {
+			if extGoFieldName, err := extParseGoFieldName(p.ExtensionProps.Extensions[extGoName]); err == nil {
+				goFieldName = extGoFieldName
+			}
+		}
+
 		// Add a comment to a field in case we have one, otherwise skip.
 		if p.Description != "" {
 			// Separate the comment from a previous-defined, unrelated field.
@@ -570,14 +582,7 @@ func GenFieldsFromProperties(props []Property) []string {
 			if i != 0 {
 				field += "\n"
 			}
-			field += fmt.Sprintf("%s\n", StringToGoComment(p.Description))
-		}
-
-		goFieldName := p.GoFieldName()
-		if _, ok := p.ExtensionProps.Extensions[extGoName]; ok {
-			if extGoFieldName, err := extParseGoFieldName(p.ExtensionProps.Extensions[extGoName]); err == nil {
-				goFieldName = extGoFieldName
-			}
+			field += fmt.Sprintf("%s\n", StringWithTypeNameToGoComment(p.Description, p.GoFieldName()))
 		}
 
 		field += fmt.Sprintf("    %s %s", goFieldName, p.GoTypeDef())
@@ -592,7 +597,7 @@ func GenFieldsFromProperties(props []Property) []string {
 
 		fieldTags := make(map[string]string)
 
-		if (p.Required && !p.ReadOnly && !p.WriteOnly) || p.Nullable || !overrideOmitEmpty {
+		if (p.Required && !p.ReadOnly && !p.WriteOnly) || p.Nullable || !overrideOmitEmpty || (p.Required && p.ReadOnly && globalState.options.Compatibility.DisableRequiredReadOnlyAsPointer) {
 			fieldTags["json"] = p.JsonFieldName
 			if p.NeedsFormTag {
 				fieldTags["form"] = p.JsonFieldName
diff --git a/pkg/codegen/template_helpers.go b/pkg/codegen/template_helpers.go
index 3ff5e1e..a677404 100644
--- a/pkg/codegen/template_helpers.go
+++ b/pkg/codegen/template_helpers.go
@@ -287,4 +287,5 @@ var TemplateFunctions = template.FuncMap{
 	"title":                      strings.Title,
 	"stripNewLines":              stripNewLines,
 	"sanitizeGoIdentity":         SanitizeGoIdentity,
+	"toGoComment":                StringWithTypeNameToGoComment,
 }
diff --git a/pkg/codegen/templates/chi/chi-middleware.tmpl b/pkg/codegen/templates/chi/chi-middleware.tmpl
index 30270cc..7311ec4 100644
--- a/pkg/codegen/templates/chi/chi-middleware.tmpl
+++ b/pkg/codegen/templates/chi/chi-middleware.tmpl
@@ -47,27 +47,32 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(w http.ResponseWriter, r *http.Requ
     // Parameter object where we will unmarshal all parameters from the context
     var params {{.OperationId}}Params
 
-    {{range $paramIdx, $param := .QueryParams}}// ------------- {{if .Required}}Required{{else}}Optional{{end}} query parameter "{{.ParamName}}" -------------
-      if paramValue := r.URL.Query().Get("{{.ParamName}}"); paramValue != "" {
+    {{range $paramIdx, $param := .QueryParams}}
+      {{- if (or (or .Required .IsPassThrough) (or .IsJson .IsStyled)) -}}
+        // ------------- {{if .Required}}Required{{else}}Optional{{end}} query parameter "{{.ParamName}}" -------------
+      {{ end }}
+      {{ if (or (or .Required .IsPassThrough) .IsJson) }}
+        if paramValue := r.URL.Query().Get("{{.ParamName}}"); paramValue != "" {
 
-      {{if .IsPassThrough}}
-        params.{{.GoName}} = {{if not .Required}}&{{end}}paramValue
-      {{end}}
+        {{if .IsPassThrough}}
+          params.{{.GoName}} = {{if not .Required}}&{{end}}paramValue
+        {{end}}
 
-      {{if .IsJson}}
-        var value {{.TypeDef}}
-        err = json.Unmarshal([]byte(paramValue), &value)
-        if err != nil {
-          siw.ErrorHandlerFunc(w, r, &UnmarshalingParamError{ParamName: "{{.ParamName}}", Err: err})
-          return
-        }
+        {{if .IsJson}}
+          var value {{.TypeDef}}
+          err = json.Unmarshal([]byte(paramValue), &value)
+          if err != nil {
+            siw.ErrorHandlerFunc(w, r, &UnmarshalingParamError{ParamName: "{{.ParamName}}", Err: err})
+            return
+          }
 
-        params.{{.GoName}} = {{if not .Required}}&{{end}}value
+          params.{{.GoName}} = {{if not .Required}}&{{end}}value
+        {{end}}
+        }{{if .Required}} else {
+            siw.ErrorHandlerFunc(w, r, &RequiredParamError{ParamName: "{{.ParamName}}"})
+            return
+        }{{end}}
       {{end}}
-      }{{if .Required}} else {
-          siw.ErrorHandlerFunc(w, r, &RequiredParamError{ParamName: "{{.ParamName}}"})
-          return
-      }{{end}}
       {{if .IsStyled}}
       err = runtime.BindQueryParameter("{{.Style}}", {{.Explode}}, {{.Required}}, "{{.ParamName}}", r.URL.Query(), &params.{{.GoName}})
       if err != nil {
diff --git a/pkg/codegen/templates/echo/echo-wrappers.tmpl b/pkg/codegen/templates/echo/echo-wrappers.tmpl
index 537751a..3402583 100644
--- a/pkg/codegen/templates/echo/echo-wrappers.tmpl
+++ b/pkg/codegen/templates/echo/echo-wrappers.tmpl
@@ -32,7 +32,10 @@ func (w *ServerInterfaceWrapper) {{.OperationId}} (ctx echo.Context) error {
 {{if .RequiresParamObject}}
     // Parameter object where we will unmarshal all parameters from the context
     var params {{.OperationId}}Params
-{{range $paramIdx, $param := .QueryParams}}// ------------- {{if .Required}}Required{{else}}Optional{{end}} query parameter "{{.ParamName}}" -------------
+{{range $paramIdx, $param := .QueryParams}}
+    {{- if (or (or .Required .IsPassThrough) (or .IsJson .IsStyled)) -}}
+      // ------------- {{if .Required}}Required{{else}}Optional{{end}} query parameter "{{.ParamName}}" -------------
+    {{ end }}
     {{if .IsStyled}}
     err = runtime.BindQueryParameter("{{.Style}}", {{.Explode}}, {{.Required}}, "{{.ParamName}}", ctx.QueryParams(), &params.{{.GoName}})
     if err != nil {
diff --git a/pkg/codegen/templates/gin/gin-wrappers.tmpl b/pkg/codegen/templates/gin/gin-wrappers.tmpl
index 27bf19c..59d03f5 100644
--- a/pkg/codegen/templates/gin/gin-wrappers.tmpl
+++ b/pkg/codegen/templates/gin/gin-wrappers.tmpl
@@ -46,27 +46,32 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(c *gin.Context) {
     // Parameter object where we will unmarshal all parameters from the context
     var params {{.OperationId}}Params
 
-    {{range $paramIdx, $param := .QueryParams}}// ------------- {{if .Required}}Required{{else}}Optional{{end}} query parameter "{{.ParamName}}" -------------
-      if paramValue := c.Query("{{.ParamName}}"); paramValue != "" {
+    {{range $paramIdx, $param := .QueryParams}}
+      {{- if (or (or .Required .IsPassThrough) (or .IsJson .IsStyled)) -}}
+        // ------------- {{if .Required}}Required{{else}}Optional{{end}} query parameter "{{.ParamName}}" -------------
+      {{ end }}
+      {{ if (or (or .Required .IsPassThrough) .IsJson) }}
+        if paramValue := c.Query("{{.ParamName}}"); paramValue != "" {
 
-      {{if .IsPassThrough}}
-        params.{{.GoName}} = {{if not .Required}}&{{end}}paramValue
-      {{end}}
+        {{if .IsPassThrough}}
+          params.{{.GoName}} = {{if not .Required}}&{{end}}paramValue
+        {{end}}
 
-      {{if .IsJson}}
-        var value {{.TypeDef}}
-        err = json.Unmarshal([]byte(paramValue), &value)
-        if err != nil {
-          c.JSON(http.StatusBadRequest, gin.H{"msg": "Error unmarshaling parameter '{{.ParamName}}' as JSON"})
-          return
-        }
+        {{if .IsJson}}
+          var value {{.TypeDef}}
+          err = json.Unmarshal([]byte(paramValue), &value)
+          if err != nil {
+            c.JSON(http.StatusBadRequest, gin.H{"msg": "Error unmarshaling parameter '{{.ParamName}}' as JSON"})
+            return
+          }
 
-        params.{{.GoName}} = {{if not .Required}}&{{end}}value
+          params.{{.GoName}} = {{if not .Required}}&{{end}}value
+        {{end}}
+        }{{if .Required}} else {
+            c.JSON(http.StatusBadRequest, gin.H{"msg": "Query argument {{.ParamName}} is required, but not found"})
+            return
+        }{{end}}
       {{end}}
-      }{{if .Required}} else {
-          c.JSON(http.StatusBadRequest, gin.H{"msg": "Query argument {{.ParamName}} is required, but not found"})
-          return
-      }{{end}}
       {{if .IsStyled}}
       err = runtime.BindQueryParameter("{{.Style}}", {{.Explode}}, {{.Required}}, "{{.ParamName}}", c.Request.URL.Query(), &params.{{.GoName}})
       if err != nil {
diff --git a/pkg/codegen/templates/gorilla/gorilla-middleware.tmpl b/pkg/codegen/templates/gorilla/gorilla-middleware.tmpl
index a08bc5e..d660a0b 100644
--- a/pkg/codegen/templates/gorilla/gorilla-middleware.tmpl
+++ b/pkg/codegen/templates/gorilla/gorilla-middleware.tmpl
@@ -47,27 +47,32 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(w http.ResponseWriter, r *http.Requ
     // Parameter object where we will unmarshal all parameters from the context
     var params {{.OperationId}}Params
 
-    {{range $paramIdx, $param := .QueryParams}}// ------------- {{if .Required}}Required{{else}}Optional{{end}} query parameter "{{.ParamName}}" -------------
-      if paramValue := r.URL.Query().Get("{{.ParamName}}"); paramValue != "" {
+    {{range $paramIdx, $param := .QueryParams}}
+      {{- if (or (or .Required .IsPassThrough) (or .IsJson .IsStyled)) -}}
+        // ------------- {{if .Required}}Required{{else}}Optional{{end}} query parameter "{{.ParamName}}" -------------
+      {{ end }}
+      {{ if (or (or .Required .IsPassThrough) .IsJson) }}
+        if paramValue := r.URL.Query().Get("{{.ParamName}}"); paramValue != "" {
 
-      {{if .IsPassThrough}}
-        params.{{.GoName}} = {{if not .Required}}&{{end}}paramValue
-      {{end}}
+        {{if .IsPassThrough}}
+          params.{{.GoName}} = {{if not .Required}}&{{end}}paramValue
+        {{end}}
 
-      {{if .IsJson}}
-        var value {{.TypeDef}}
-        err = json.Unmarshal([]byte(paramValue), &value)
-        if err != nil {
-          siw.ErrorHandlerFunc(w, r, &UnmarshalingParamError{ParamName: "{{.ParamName}}", Err: err})
-          return
-        }
+        {{if .IsJson}}
+          var value {{.TypeDef}}
+          err = json.Unmarshal([]byte(paramValue), &value)
+          if err != nil {
+            siw.ErrorHandlerFunc(w, r, &UnmarshalingParamError{ParamName: "{{.ParamName}}", Err: err})
+            return
+          }
 
-        params.{{.GoName}} = {{if not .Required}}&{{end}}value
+          params.{{.GoName}} = {{if not .Required}}&{{end}}value
+        {{end}}
+        }{{if .Required}} else {
+            siw.ErrorHandlerFunc(w, r, &RequiredParamError{ParamName: "{{.ParamName}}"})
+            return
+        }{{end}}
       {{end}}
-      }{{if .Required}} else {
-          siw.ErrorHandlerFunc(w, r, &RequiredParamError{ParamName: "{{.ParamName}}"})
-          return
-      }{{end}}
       {{if .IsStyled}}
       err = runtime.BindQueryParameter("{{.Style}}", {{.Explode}}, {{.Required}}, "{{.ParamName}}", r.URL.Query(), &params.{{.GoName}})
       if err != nil {
@@ -112,7 +117,7 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(w http.ResponseWriter, r *http.Requ
           params.{{.GoName}} = {{if not .Required}}&{{end}}{{.GoName}}
 
         } {{if .Required}}else {
-            err := fmt.Errorf("Header parameter {{.ParamName}} is required, but not found")
+            err = fmt.Errorf("Header parameter {{.ParamName}} is required, but not found")
             siw.ErrorHandlerFunc(w, r, &RequiredHeaderError{ParamName: "{{.ParamName}}", Err: err})
             return
         }{{end}}
diff --git a/pkg/codegen/templates/strict/strict-chi.tmpl b/pkg/codegen/templates/strict/strict-chi.tmpl
index ba2da83..c8465db 100644
--- a/pkg/codegen/templates/strict/strict-chi.tmpl
+++ b/pkg/codegen/templates/strict/strict-chi.tmpl
@@ -2,13 +2,30 @@ type StrictHandlerFunc func(ctx context.Context, w http.ResponseWriter, r *http.
 
 type StrictMiddlewareFunc func(f StrictHandlerFunc, operationID string) StrictHandlerFunc
 
+type StrictChiServerOptions struct {
+    RequestErrorHandlerFunc  func(w http.ResponseWriter, r *http.Request, err error)
+    ResponseErrorHandlerFunc func(w http.ResponseWriter, r *http.Request, err error)
+}
+
 func NewStrictHandler(ssi StrictServerInterface, middlewares []StrictMiddlewareFunc) ServerInterface {
-    return &strictHandler{ssi: ssi, middlewares: middlewares}
+    return &strictHandler{ssi: ssi, middlewares: middlewares, options: StrictChiServerOptions {
+        RequestErrorHandlerFunc: func(w http.ResponseWriter, r *http.Request, err error) {
+            http.Error(w, err.Error(), http.StatusBadRequest)
+        },
+        ResponseErrorHandlerFunc: func(w http.ResponseWriter, r *http.Request, err error) {
+            http.Error(w, err.Error(), http.StatusInternalServerError)
+        },
+    }}
+}
+
+func NewStrictHandlerWithOptions(ssi StrictServerInterface, middlewares []StrictMiddlewareFunc, options StrictChiServerOptions) ServerInterface {
+    return &strictHandler{ssi: ssi, middlewares: middlewares, options: options}
 }
 
 type strictHandler struct {
     ssi StrictServerInterface
     middlewares []StrictMiddlewareFunc
+    options StrictChiServerOptions
 }
 
 {{range .}}
@@ -36,24 +53,24 @@ type strictHandler struct {
                 {{if eq .NameTag "JSON" -}}
                     var body {{$opid}}{{.NameTag}}RequestBody
                     if err := json.NewDecoder(r.Body).Decode(&body); err != nil {
-                        http.Error(w, "can't decode JSON body: " + err.Error(), http.StatusBadRequest)
+                        sh.options.RequestErrorHandlerFunc(w, r, fmt.Errorf("can't decode JSON body: %w", err))
                         return
                     }
                     request.{{if $multipleBodies}}{{.NameTag}}{{end}}Body = &body
                 {{else if eq .NameTag "Formdata" -}}
                     if err := r.ParseForm(); err != nil {
-                        http.Error(w, "can't decode formdata: " + err.Error(), http.StatusBadRequest)
+                        sh.options.RequestErrorHandlerFunc(w, r, fmt.Errorf("can't decode formdata: %w", err))
                         return
                     }
                     var body {{$opid}}{{.NameTag}}RequestBody
                     if err := runtime.BindForm(&body, r.Form, nil, nil); err != nil {
-                        http.Error(w, "can't bind formdata: " + err.Error(), http.StatusBadRequest)
+                        sh.options.RequestErrorHandlerFunc(w, r, fmt.Errorf("can't bind formdata: %w", err))
                         return
                     }
                     request.{{if $multipleBodies}}{{.NameTag}}{{end}}Body = &body
                 {{else if eq .NameTag "Multipart" -}}
                     if reader, err := r.MultipartReader(); err != nil {
-                        http.Error(w, "can't decode multipart body: " + err.Error(), http.StatusBadRequest)
+                        sh.options.RequestErrorHandlerFunc(w, r, fmt.Errorf("can't decode multipart body: %w", err))
                         return
                     } else {
                         request.{{if $multipleBodies}}{{.NameTag}}{{end}}Body = reader
@@ -61,7 +78,7 @@ type strictHandler struct {
                 {{else if eq .NameTag "Text" -}}
                     data, err := ioutil.ReadAll(r.Body)
                     if err != nil {
-                        http.Error(w, "can't read body: " + err.Error(), http.StatusBadRequest)
+                        sh.options.RequestErrorHandlerFunc(w, r, fmt.Errorf("can't read body: %w", err))
                         return
                     }
                     body := {{$opid}}{{.NameTag}}RequestBody(data)
@@ -114,7 +131,7 @@ type strictHandler struct {
                     {{else if eq .NameTag "Multipart" -}}
                         defer writer.Close()
                         if err := v(writer); err != nil {
-                            http.Error(w, err.Error(), http.StatusInternalServerError)
+                            sh.options.ResponseErrorHandlerFunc(w, r, err)
                         }
                     {{else -}}
                         if closer, ok := v.Body.(io.ReadCloser); ok {
@@ -132,10 +149,10 @@ type strictHandler struct {
                 {{end}}{{/* if eq 0 (len .Contents) */ -}}
             {{end}}{{/* range .Responses */ -}}
             case error:
-                http.Error(w, v.Error(), http.StatusInternalServerError)
+                sh.options.ResponseErrorHandlerFunc(w, r, v)
             case nil:
             default:
-                http.Error(w, fmt.Sprintf("Unexpected response type: %T", v), http.StatusInternalServerError)
+                sh.options.ResponseErrorHandlerFunc(w, r, fmt.Errorf("Unexpected response type: %T", v))
         }
     }
 {{end}}
diff --git a/pkg/codegen/templates/typedef.tmpl b/pkg/codegen/templates/typedef.tmpl
index e5a6a82..be3112c 100644
--- a/pkg/codegen/templates/typedef.tmpl
+++ b/pkg/codegen/templates/typedef.tmpl
@@ -1,4 +1,4 @@
 {{range .Types}}
-{{ with .Schema.Description }}{{ . }}{{ else }}// {{.TypeName}} defines model for {{.JsonName}}.{{ end }}
+{{ if .Schema.Description }}{{ toGoComment .Schema.Description .TypeName  }}{{ else }}// {{.TypeName}} defines model for {{.JsonName}}.{{ end }}
 type {{.TypeName}} {{if .IsAlias }}={{end}} {{.Schema.TypeDecl}}
 {{end}}
diff --git a/pkg/codegen/templates/union.tmpl b/pkg/codegen/templates/union.tmpl
index a29e2d0..d233e13 100644
--- a/pkg/codegen/templates/union.tmpl
+++ b/pkg/codegen/templates/union.tmpl
@@ -4,12 +4,14 @@
     {{$properties := .Schema.Properties -}}
     {{range .Schema.UnionElements}}
         {{$element := . -}}
+        // As{{.}} returns the union data inside the {{$typeName}} as a {{.}}
         func (t {{$typeName}}) As{{.}}() ({{.}}, error) {
             var body {{.}}
             err := json.Unmarshal(t.union, &body)
             return body, err
         }
 
+        // From{{.}} overwrites any union data inside the {{$typeName}} as the provided {{.}}
         func (t *{{$typeName}}) From{{.}} (v {{.}}) error {
             {{if $discriminator -}}
                 {{range $value, $type := $discriminator.Mapping -}}
@@ -29,6 +31,32 @@
             t.union = b
             return err
         }
+
+        // Merge{{.}} performs a merge with any union data inside the {{$typeName}}, using the provided {{.}}
+        func (t *{{$typeName}}) Merge{{.}} (v {{.}}) error {
+            {{if $discriminator -}}
+                {{range $value, $type := $discriminator.Mapping -}}
+                    {{if eq $type $element -}}
+                        {{$hasProperty := false -}}
+                        {{range $properties -}}
+                            {{if eq .GoFieldName $discriminator.PropertyName -}}
+                                t.{{$discriminator.PropertyName}} = "{{$value}}"
+                                {{$hasProperty = true -}}
+                            {{end -}}
+                        {{end -}}
+                        {{if not $hasProperty}}v.{{$discriminator.PropertyName}} = "{{$value}}"{{end}}
+                    {{end -}}
+                {{end -}}
+            {{end -}}
+            b, err := json.Marshal(v)
+            if err != nil {
+              return err
+            }
+
+            merged, err := runtime.JsonMerge(b, t.union)
+            t.union = merged
+            return err
+        }
     {{end}}
 
     {{if $discriminator}}
@@ -65,9 +93,11 @@
                 return nil, err
             }
             object := make(map[string]json.RawMessage)
-            err = json.Unmarshal(b, &object)
-            if err != nil {
+            if t.union != nil {
+              err = json.Unmarshal(b, &object)
+              if err != nil {
                 return nil, err
+              }
             }
             {{range .Schema.Properties}}
                 object["{{.JsonFieldName}}"], err = json.Marshal(t.{{.GoFieldName}})
@@ -102,4 +132,4 @@
         {{end -}}
         return err
     }
-{{end}}
\ No newline at end of file
+{{end}}
diff --git a/pkg/codegen/utils.go b/pkg/codegen/utils.go
index 557b919..fe25353 100644
--- a/pkg/codegen/utils.go
+++ b/pkg/codegen/utils.go
@@ -14,6 +14,7 @@
 package codegen
 
 import (
+	"encoding/json"
 	"fmt"
 	"net/url"
 	"regexp"
@@ -603,6 +604,8 @@ func typeNamePrefix(name string) (prefix string) {
 			prefix += "Asterisk"
 		case '^':
 			prefix += "Caret"
+		case '%':
+			prefix += "Percent"
 		default:
 			// Prepend "N" to schemas starting with a number
 			if prefix == "" && unicode.IsDigit(r) {
@@ -652,6 +655,17 @@ func PathToTypeName(path []string) string {
 // StringToGoComment renders a possible multi-line string as a valid Go-Comment.
 // Each line is prefixed as a comment.
 func StringToGoComment(in string) string {
+	return stringToGoCommentWithPrefix(in, "")
+}
+
+// StringWithTypeNameToGoComment renders a possible multi-line string as a
+// valid Go-Comment, including the name of the type being referenced. Each line
+// is prefixed as a comment.
+func StringWithTypeNameToGoComment(in, typeName string) string {
+	return stringToGoCommentWithPrefix(in, typeName)
+}
+
+func stringToGoCommentWithPrefix(in, prefix string) string {
 	if len(in) == 0 || len(strings.TrimSpace(in)) == 0 { // ignore empty comment
 		return ""
 	}
@@ -662,8 +676,12 @@ func StringToGoComment(in string) string {
 
 	// Add comment to each line
 	var lines []string
-	for _, line := range strings.Split(in, "\n") {
-		lines = append(lines, fmt.Sprintf("// %s", line))
+	for i, line := range strings.Split(in, "\n") {
+		s := "//"
+		if i == 0 && len(prefix) > 0 {
+			s += " " + prefix
+		}
+		lines = append(lines, fmt.Sprintf("%s %s", s, line))
 	}
 	in = strings.Join(lines, "\n")
 
@@ -801,3 +819,28 @@ func findSchemaNameByRefPath(refPath string, spec *openapi3.T) (string, error) {
 	}
 	return "", nil
 }
+
+func GetImports(dict map[string]*openapi3.SchemaRef) (map[string]goImport, error) {
+	res := map[string]goImport{}
+	for _, v := range dict {
+		if v == nil || v.Value == nil {
+			continue
+		}
+
+		if v.Value.Extensions["x-go-type-import"] == nil || v.Value.Extensions["x-go-type"] == nil {
+			continue
+		}
+		goTypeImportExt := v.Value.Extensions["x-go-type-import"]
+
+		if raw, ok := goTypeImportExt.(json.RawMessage); ok {
+			gi := goImport{}
+			if err := json.Unmarshal(raw, &gi); err != nil {
+				return nil, err
+			}
+			res[gi.String()] = gi
+		} else {
+			continue
+		}
+	}
+	return res, nil
+}
diff --git a/pkg/runtime/jsonmerge.go b/pkg/runtime/jsonmerge.go
new file mode 100644
index 0000000..155abfb
--- /dev/null
+++ b/pkg/runtime/jsonmerge.go
@@ -0,0 +1,26 @@
+package runtime
+
+import (
+	"encoding/json"
+
+	"github.com/apapsch/go-jsonmerge/v2"
+)
+
+// JsonMerge merges two JSON representation into a single object. `data` is the
+// existing representation and `patch` is the new data to be merged in
+func JsonMerge(data, patch json.RawMessage) (json.RawMessage, error) {
+	merger := jsonmerge.Merger{
+		CopyNonexistent: true,
+	}
+	if data == nil {
+		data = []byte(`{}`)
+	}
+	if patch == nil {
+		patch = []byte(`{}`)
+	}
+	merged, err := merger.MergeBytes(data, patch)
+	if err != nil {
+		return nil, err
+	}
+	return merged, nil
+}
diff --git a/pkg/types/date.go b/pkg/types/date.go
index ffc665c..6ad852f 100644
--- a/pkg/types/date.go
+++ b/pkg/types/date.go
@@ -32,3 +32,12 @@ func (d *Date) UnmarshalJSON(data []byte) error {
 func (d Date) String() string {
 	return d.Time.Format(DateFormat)
 }
+
+func (d *Date) UnmarshalText(data []byte) error {
+	parsed, err := time.Parse(DateFormat, string(data))
+	if err != nil {
+		return err
+	}
+	d.Time = parsed
+	return nil
+}


Test patch:
diff --git a/internal/test/all_of/v1/openapi.gen.go b/internal/test/all_of/v1/openapi.gen.go
index 8092ab3..0023261 100644
--- a/internal/test/all_of/v1/openapi.gen.go
+++ b/internal/test/all_of/v1/openapi.gen.go
@@ -22,7 +22,7 @@ type Person struct {
 	// Embedded fields due to inline allOf schema
 }
 
-// These are fields that specify a person. They are all optional, and
+// PersonProperties These are fields that specify a person. They are all optional, and
 // would be used by an `Edit` style API endpoint, where each is optional.
 type PersonProperties struct {
 	FirstName          *string `json:"FirstName,omitempty"`
diff --git a/internal/test/all_of/v2/openapi.gen.go b/internal/test/all_of/v2/openapi.gen.go
index f2bd6cb..3222dcf 100644
--- a/internal/test/all_of/v2/openapi.gen.go
+++ b/internal/test/all_of/v2/openapi.gen.go
@@ -22,7 +22,7 @@ type Person struct {
 	LastName           string `json:"LastName"`
 }
 
-// These are fields that specify a person. They are all optional, and
+// PersonProperties These are fields that specify a person. They are all optional, and
 // would be used by an `Edit` style API endpoint, where each is optional.
 type PersonProperties struct {
 	FirstName          *string `json:"FirstName,omitempty"`
diff --git a/internal/test/components/components.gen.go b/internal/test/components/components.gen.go
index 37b0cef..98d794d 100644
--- a/internal/test/components/components.gen.go
+++ b/internal/test/components/components.gen.go
@@ -7,6 +7,8 @@ import (
 	"encoding/json"
 	"errors"
 	"fmt"
+
+	"github.com/deepmap/oapi-codegen/pkg/runtime"
 )
 
 // Defines values for Enum1.
@@ -66,6 +68,7 @@ const (
 	FunnyValuesAsterisk FunnyValues = "*"
 	FunnyValuesEmpty    FunnyValues = ""
 	FunnyValuesN5       FunnyValues = "5"
+	FunnyValuesPercent  FunnyValues = "%"
 )
 
 // Defines values for EnumParam1.
@@ -89,7 +92,7 @@ const (
 	Eve   EnumParam3 = "eve"
 )
 
-// Has additional properties of type int
+// AdditionalPropertiesObject1 Has additional properties of type int
 type AdditionalPropertiesObject1 struct {
 	Id                   int            `json:"id"`
 	Name                 string         `json:"name"`
@@ -97,19 +100,19 @@ type AdditionalPropertiesObject1 struct {
 	AdditionalProperties map[string]int `json:"-"`
 }
 
-// Does not allow additional properties
+// AdditionalPropertiesObject2 Does not allow additional properties
 type AdditionalPropertiesObject2 struct {
 	Id   int    `json:"id"`
 	Name string `json:"name"`
 }
 
-// Allows any additional property
+// AdditionalPropertiesObject3 Allows any additional property
 type AdditionalPropertiesObject3 struct {
 	Name                 string                 `json:"name"`
 	AdditionalProperties map[string]interface{} `json:"-"`
 }
 
-// Has anonymous field which has additional properties
+// AdditionalPropertiesObject4 Has anonymous field which has additional properties
 type AdditionalPropertiesObject4 struct {
 	Inner                AdditionalPropertiesObject4_Inner `json:"inner"`
 	Name                 string                            `json:"name"`
@@ -122,33 +125,33 @@ type AdditionalPropertiesObject4_Inner struct {
 	AdditionalProperties map[string]interface{} `json:"-"`
 }
 
-// Has additional properties with schema for dictionaries
+// AdditionalPropertiesObject5 Has additional properties with schema for dictionaries
 type AdditionalPropertiesObject5 map[string]SchemaObject
 
-// Array of object with additional properties
+// AdditionalPropertiesObject6 Array of object with additional properties
 type AdditionalPropertiesObject6 = []map[string]SchemaObject
 
-// simple anyOf case
+// AnyOfObject1 simple anyOf case
 type AnyOfObject1 struct {
 	union json.RawMessage
 }
 
-// Conflicts with Enum2, enum values need to be prefixed with type
+// Enum1 Conflicts with Enum2, enum values need to be prefixed with type
 // name.
 type Enum1 string
 
-// Conflicts with Enum1, enum values need to be prefixed with type
+// Enum2 Conflicts with Enum1, enum values need to be prefixed with type
 // name.
 type Enum2 string
 
-// Enum values conflict with Enums above, need to be prefixed
+// Enum3 Enum values conflict with Enums above, need to be prefixed
 // with type name.
 type Enum3 string
 
-// No conflicts here, should have unmodified enums
+// Enum4 No conflicts here, should have unmodified enums
 type Enum4 string
 
-// Numerical enum
+// Enum5 Numerical enum
 type Enum5 int
 
 // EnumUnion defines model for EnumUnion.
@@ -157,7 +160,7 @@ type EnumUnion string
 // EnumUnion2 defines model for EnumUnion2.
 type EnumUnion2 string
 
-// Edge cases for enum names
+// FunnyValues Edge cases for enum names
 type FunnyValues string
 
 // ObjectWithJsonField defines model for ObjectWithJsonField.
@@ -167,12 +170,12 @@ type ObjectWithJsonField struct {
 	Value2 json.RawMessage `json:"value2,omitempty"`
 }
 
-// oneOf with references and no disciminator
+// OneOfObject1 oneOf with references and no disciminator
 type OneOfObject1 struct {
 	union json.RawMessage
 }
 
-// fixed properties, variable required - will compile, but not much sense
+// OneOfObject10 fixed properties, variable required - will compile, but not much sense
 type OneOfObject10 struct {
 	One   *string `json:"one,omitempty"`
 	Three *bool   `json:"three,omitempty"`
@@ -186,7 +189,7 @@ type OneOfObject100 = interface{}
 // OneOfObject101 defines model for .
 type OneOfObject101 = interface{}
 
-// additional properties of oneOf
+// OneOfObject11 additional properties of oneOf
 type OneOfObject11 map[string]OneOfObject11_AdditionalProperties
 
 // OneOfObject110 defines model for .
@@ -214,7 +217,7 @@ type OneOfObject120 = string
 // OneOfObject121 defines model for .
 type OneOfObject121 = float32
 
-// oneOf with inline elements
+// OneOfObject2 oneOf with inline elements
 type OneOfObject2 struct {
 	union json.RawMessage
 }
@@ -230,7 +233,7 @@ type OneOfObject21 = []float32
 // OneOfObject22 defines model for .
 type OneOfObject22 = bool
 
-// inline OneOf
+// OneOfObject3 inline OneOf
 type OneOfObject3 struct {
 	Union *OneOfObject3_Union `json:"union,omitempty"`
 }
@@ -240,23 +243,23 @@ type OneOfObject3_Union struct {
 	union json.RawMessage
 }
 
-// oneOf plus fixed type - custom marshaling/unmarshaling
+// OneOfObject4 oneOf plus fixed type - custom marshaling/unmarshaling
 type OneOfObject4 struct {
 	FixedProperty *string `json:"fixedProperty,omitempty"`
 	union         json.RawMessage
 }
 
-// oneOf with disciminator but no mapping
+// OneOfObject5 oneOf with disciminator but no mapping
 type OneOfObject5 struct {
 	union json.RawMessage
 }
 
-// oneOf with discriminator and mapping
+// OneOfObject6 oneOf with discriminator and mapping
 type OneOfObject6 struct {
 	union json.RawMessage
 }
 
-// array of oneOf
+// OneOfObject7 array of oneOf
 type OneOfObject7 = []OneOfObject7_Item
 
 // OneOfObject7_Item defines model for OneOfObject7.Item.
@@ -264,13 +267,13 @@ type OneOfObject7_Item struct {
 	union json.RawMessage
 }
 
-// oneOf with fixed properties
+// OneOfObject8 oneOf with fixed properties
 type OneOfObject8 struct {
 	Fixed *string `json:"fixed,omitempty"`
 	union json.RawMessage
 }
 
-// oneOf with fixed descriminator
+// OneOfObject9 oneOf with fixed descriminator
 type OneOfObject9 struct {
 	Type  string `json:"type"`
 	union json.RawMessage
@@ -304,13 +307,13 @@ type OneOfVariant6 struct {
 	Values OneOfVariant2 `json:"values"`
 }
 
-// When a Schema is renamed, $ref should refer to the new name
+// ReferenceToRenameMe When a Schema is renamed, $ref should refer to the new name
 type ReferenceToRenameMe struct {
-	// This schema should be renamed via x-go-name when generating
+	// ToNewName This schema should be renamed via x-go-name when generating
 	NewName NewName `json:"ToNewName"`
 }
 
-// This schema should be renamed via x-go-name when generating
+// NewName This schema should be renamed via x-go-name when generating
 type NewName struct {
 	Prop1 string `json:"prop1"`
 	Prop2 string `json:"prop2"`
@@ -320,7 +323,7 @@ type NewName struct {
 type SchemaObject struct {
 	FirstName string `json:"firstName"`
 
-	// This property is required and readOnly, so the go model should have it as a pointer,
+	// ReadOnlyRequiredProp This property is required and readOnly, so the go model should have it as a pointer,
 	// as it will not be included when it is sent from client to server.
 	ReadOnlyRequiredProp  *string `json:"readOnlyRequiredProp,omitempty"`
 	Role                  string  `json:"role"`
@@ -336,7 +339,7 @@ type EnumParam2 string
 // EnumParam3 defines model for EnumParam3.
 type EnumParam3 string
 
-// a parameter
+// RenamedParameterObject // a parameter
 type RenamedParameterObject string
 
 // RenamedResponseObject defines model for ResponseObject.
@@ -349,20 +352,20 @@ type RenamedRequestBody struct {
 	Field SchemaObject `json:"Field"`
 }
 
+// EnsureEverythingIsReferencedTextBody defines parameters for EnsureEverythingIsReferenced.
+type EnsureEverythingIsReferencedTextBody = string
+
 // EnsureEverythingIsReferencedJSONBody defines parameters for EnsureEverythingIsReferenced.
 type EnsureEverythingIsReferencedJSONBody struct {
 	Field SchemaObject `json:"Field"`
 }
 
-// EnsureEverythingIsReferencedTextBody defines parameters for EnsureEverythingIsReferenced.
-type EnsureEverythingIsReferencedTextBody = string
-
 // ParamsWithAddPropsParams defines parameters for ParamsWithAddProps.
 type ParamsWithAddPropsParams struct {
-	// This parameter has additional properties
+	// P1 This parameter has additional properties
 	P1 map[string]interface{} `json:"p1"`
 
-	// This parameter has an anonymous inner property which needs to be
+	// P2 This parameter has an anonymous inner property which needs to be
 	// turned into a proper type for additionalProperties to work
 	P2 struct {
 		Inner map[string]string `json:"inner"`
@@ -769,30 +772,58 @@ func (a AdditionalPropertiesObject4_Inner) MarshalJSON() ([]byte, error) {
 	return json.Marshal(object)
 }
 
+// AsOneOfVariant4 returns the union data inside the AnyOfObject1 as a OneOfVariant4
 func (t AnyOfObject1) AsOneOfVariant4() (OneOfVariant4, error) {
 	var body OneOfVariant4
 	err := json.Unmarshal(t.union, &body)
 	return body, err
 }
 
+// FromOneOfVariant4 overwrites any union data inside the AnyOfObject1 as the provided OneOfVariant4
 func (t *AnyOfObject1) FromOneOfVariant4(v OneOfVariant4) error {
 	b, err := json.Marshal(v)
 	t.union = b
 	return err
 }
 
+// MergeOneOfVariant4 performs a merge with any union data inside the AnyOfObject1, using the provided OneOfVariant4
+func (t *AnyOfObject1) MergeOneOfVariant4(v OneOfVariant4) error {
+	b, err := json.Marshal(v)
+	if err != nil {
+		return err
+	}
+
+	merged, err := runtime.JsonMerge(b, t.union)
+	t.union = merged
+	return err
+}
+
+// AsOneOfVariant5 returns the union data inside the AnyOfObject1 as a OneOfVariant5
 func (t AnyOfObject1) AsOneOfVariant5() (OneOfVariant5, error) {
 	var body OneOfVariant5
 	err := json.Unmarshal(t.union, &body)
 	return body, err
 }
 
+// FromOneOfVariant5 overwrites any union data inside the AnyOfObject1 as the provided OneOfVariant5
 func (t *AnyOfObject1) FromOneOfVariant5(v OneOfVariant5) error {
 	b, err := json.Marshal(v)
 	t.union = b
 	return err
 }
 
+// MergeOneOfVariant5 performs a merge with any union data inside the AnyOfObject1, using the provided OneOfVariant5
+func (t *AnyOfObject1) MergeOneOfVariant5(v OneOfVariant5) error {
+	b, err := json.Marshal(v)
+	if err != nil {
+		return err
+	}
+
+	merged, err := runtime.JsonMerge(b, t.union)
+	t.union = merged
+	return err
+}
+
 func (t AnyOfObject1) MarshalJSON() ([]byte, error) {
 	b, err := t.union.MarshalJSON()
 	return b, err
@@ -803,42 +834,84 @@ func (t *AnyOfObject1) UnmarshalJSON(b []byte) error {
 	return err
 }
 
+// AsOneOfVariant1 returns the union data inside the OneOfObject1 as a OneOfVariant1
 func (t OneOfObject1) AsOneOfVariant1() (OneOfVariant1, error) {
 	var body OneOfVariant1
 	err := json.Unmarshal(t.union, &body)
 	return body, err
 }
 
+// FromOneOfVariant1 overwrites any union data inside the OneOfObject1 as the provided OneOfVariant1
 func (t *OneOfObject1) FromOneOfVariant1(v OneOfVariant1) error {
 	b, err := json.Marshal(v)
 	t.union = b
 	return err
 }
 
+// MergeOneOfVariant1 performs a merge with any union data inside the OneOfObject1, using the provided OneOfVariant1
+func (t *OneOfObject1) MergeOneOfVariant1(v OneOfVariant1) error {
+	b, err := json.Marshal(v)
+	if err != nil {
+		return err
+	}
+
+	merged, err := runtime.JsonMerge(b, t.union)
+	t.union = merged
+	return err
+}
+
+// AsOneOfVariant2 returns the union data inside the OneOfObject1 as a OneOfVariant2
 func (t OneOfObject1) AsOneOfVariant2() (OneOfVariant2, error) {
 	var body OneOfVariant2
 	err := json.Unmarshal(t.union, &body)
 	return body, err
 }
 
+// FromOneOfVariant2 overwrites any union data inside the OneOfObject1 as the provided OneOfVariant2
 func (t *OneOfObject1) FromOneOfVariant2(v OneOfVariant2) error {
 	b, err := json.Marshal(v)
 	t.union = b
 	return err
 }
 
+// MergeOneOfVariant2 performs a merge with any union data inside the OneOfObject1, using the provided OneOfVariant2
+func (t *OneOfObject1) MergeOneOfVariant2(v OneOfVariant2) error {
+	b, err := json.Marshal(v)
+	if err != nil {
+		return err
+	}
+
+	merged, err := runtime.JsonMerge(b, t.union)
+	t.union = merged
+	return err
+}
+
+// AsOneOfVariant3 returns the union data inside the OneOfObject1 as a OneOfVariant3
 func (t OneOfObject1) AsOneOfVariant3() (OneOfVariant3, error) {
 	var body OneOfVariant3
 	err := json.Unmarshal(t.union, &body)
 	return body, err
 }
 
+// FromOneOfVariant3 overwrites any union data inside the OneOfObject1 as the provided OneOfVariant3
 func (t *OneOfObject1) FromOneOfVariant3(v OneOfVariant3) error {
 	b, err := json.Marshal(v)
 	t.union = b
 	return err
 }
 
+// MergeOneOfVariant3 performs a merge with any union data inside the OneOfObject1, using the provided OneOfVariant3
+func (t *OneOfObject1) MergeOneOfVariant3(v OneOfVariant3) error {
+	b, err := json.Marshal(v)
+	if err != nil {
+		return err
+	}
+
+	merged, err := runtime.JsonMerge(b, t.union)
+	t.union = merged
+	return err
+}
+
 func (t OneOfObject1) MarshalJSON() ([]byte, error) {
 	b, err := t.union.MarshalJSON()
 	return b, err
@@ -849,39 +922,69 @@ func (t *OneOfObject1) UnmarshalJSON(b []byte) error {
 	return err
 }
 
+// AsOneOfObject100 returns the union data inside the OneOfObject10 as a OneOfObject100
 func (t OneOfObject10) AsOneOfObject100() (OneOfObject100, error) {
 	var body OneOfObject100
 	err := json.Unmarshal(t.union, &body)
 	return body, err
 }
 
+// FromOneOfObject100 overwrites any union data inside the OneOfObject10 as the provided OneOfObject100
 func (t *OneOfObject10) FromOneOfObject100(v OneOfObject100) error {
 	b, err := json.Marshal(v)
 	t.union = b
 	return err
 }
 
+// MergeOneOfObject100 performs a merge with any union data inside the OneOfObject10, using the provided OneOfObject100
+func (t *OneOfObject10) MergeOneOfObject100(v OneOfObject100) error {
+	b, err := json.Marshal(v)
+	if err != nil {
+		return err
+	}
+
+	merged, err := runtime.JsonMerge(b, t.union)
+	t.union = merged
+	return err
+}
+
+// AsOneOfObject101 returns the union data inside the OneOfObject10 as a OneOfObject101
 func (t OneOfObject10) AsOneOfObject101() (OneOfObject101, error) {
 	var body OneOfObject101
 	err := json.Unmarshal(t.union, &body)
 	return body, err
 }
 
+// FromOneOfObject101 overwrites any union data inside the OneOfObject10 as the provided OneOfObject101
 func (t *OneOfObject10) FromOneOfObject101(v OneOfObject101) error {
 	b, err := json.Marshal(v)
 	t.union = b
 	return err
 }
 
+// MergeOneOfObject101 performs a merge with any union data inside the OneOfObject10, using the provided OneOfObject101
+func (t *OneOfObject10) MergeOneOfObject101(v OneOfObject101) error {
+	b, err := json.Marshal(v)
+	if err != nil {
+		return err
+	}
+
+	merged, err := runtime.JsonMerge(b, t.union)
+	t.union = merged
+	return err
+}
+
 func (t OneOfObject10) MarshalJSON() ([]byte, error) {
 	b, err := t.union.MarshalJSON()
 	if err != nil {
 		return nil, err
 	}
 	object := make(map[string]json.RawMessage)
-	err = json.Unmarshal(b, &object)
-	if err != nil {
-		return nil, err
+	if t.union != nil {
+		err = json.Unmarshal(b, &object)
+		if err != nil {
+			return nil, err
+		}
 	}
 
 	object["one"], err = json.Marshal(t.One)
@@ -937,42 +1040,84 @@ func (t *OneOfObject10) UnmarshalJSON(b []byte) error {
 	return err
 }
 
+// AsOneOfObject110 returns the union data inside the OneOfObject11_AdditionalProperties as a OneOfObject110
 func (t OneOfObject11_AdditionalProperties) AsOneOfObject110() (OneOfObject110, error) {
 	var body OneOfObject110
 	err := json.Unmarshal(t.union, &body)
 	return body, err
 }
 
+// FromOneOfObject110 overwrites any union data inside the OneOfObject11_AdditionalProperties as the provided OneOfObject110
 func (t *OneOfObject11_AdditionalProperties) FromOneOfObject110(v OneOfObject110) error {
 	b, err := json.Marshal(v)
 	t.union = b
 	return err
 }
 
+// MergeOneOfObject110 performs a merge with any union data inside the OneOfObject11_AdditionalProperties, using the provided OneOfObject110
+func (t *OneOfObject11_AdditionalProperties) MergeOneOfObject110(v OneOfObject110) error {
+	b, err := json.Marshal(v)
+	if err != nil {
+		return err
+	}
+
+	merged, err := runtime.JsonMerge(b, t.union)
+	t.union = merged
+	return err
+}
+
+// AsOneOfObject111 returns the union data inside the OneOfObject11_AdditionalProperties as a OneOfObject111
 func (t OneOfObject11_AdditionalProperties) AsOneOfObject111() (OneOfObject111, error) {
 	var body OneOfObject111
 	err := json.Unmarshal(t.union, &body)
 	return body, err
 }
 
+// FromOneOfObject111 overwrites any union data inside the OneOfObject11_AdditionalProperties as the provided OneOfObject111
 func (t *OneOfObject11_AdditionalProperties) FromOneOfObject111(v OneOfObject111) error {
 	b, err := json.Marshal(v)
 	t.union = b
 	return err
 }
 
+// MergeOneOfObject111 performs a merge with any union data inside the OneOfObject11_AdditionalProperties, using the provided OneOfObject111
+func (t *OneOfObject11_AdditionalProperties) MergeOneOfObject111(v OneOfObject111) error {
+	b, err := json.Marshal(v)
+	if err != nil {
+		return err
+	}
+
+	merged, err := runtime.JsonMerge(b, t.union)
+	t.union = merged
+	return err
+}
+
+// AsOneOfObject112 returns the union data inside the OneOfObject11_AdditionalProperties as a OneOfObject112
 func (t OneOfObject11_AdditionalProperties) AsOneOfObject112() (OneOfObject112, error) {
 	var body OneOfObject112
 	err := json.Unmarshal(t.union, &body)
 	return body, err
 }
 
+// FromOneOfObject112 overwrites any union data inside the OneOfObject11_AdditionalProperties as the provided OneOfObject112
 func (t *OneOfObject11_AdditionalProperties) FromOneOfObject112(v OneOfObject112) error {
 	b, err := json.Marshal(v)
 	t.union = b
 	return err
 }
 
+// MergeOneOfObject112 performs a merge with any union data inside the OneOfObject11_AdditionalProperties, using the provided OneOfObject112
+func (t *OneOfObject11_AdditionalProperties) MergeOneOfObject112(v OneOfObject112) error {
+	b, err := json.Marshal(v)
+	if err != nil {
+		return err
+	}
+
+	merged, err := runtime.JsonMerge(b, t.union)
+	t.union = merged
+	return err
+}
+
 func (t OneOfObject11_AdditionalProperties) MarshalJSON() ([]byte, error) {
 	b, err := t.union.MarshalJSON()
 	return b, err
@@ -983,54 +1128,110 @@ func (t *OneOfObject11_AdditionalProperties) UnmarshalJSON(b []byte) error {
 	return err
 }
 
+// AsOneOfObject120 returns the union data inside the OneOfObject12 as a OneOfObject120
 func (t OneOfObject12) AsOneOfObject120() (OneOfObject120, error) {
 	var body OneOfObject120
 	err := json.Unmarshal(t.union, &body)
 	return body, err
 }
 
+// FromOneOfObject120 overwrites any union data inside the OneOfObject12 as the provided OneOfObject120
 func (t *OneOfObject12) FromOneOfObject120(v OneOfObject120) error {
 	b, err := json.Marshal(v)
 	t.union = b
 	return err
 }
 
+// MergeOneOfObject120 performs a merge with any union data inside the OneOfObject12, using the provided OneOfObject120
+func (t *OneOfObject12) MergeOneOfObject120(v OneOfObject120) error {
+	b, err := json.Marshal(v)
+	if err != nil {
+		return err
+	}
+
+	merged, err := runtime.JsonMerge(b, t.union)
+	t.union = merged
+	return err
+}
+
+// AsOneOfObject121 returns the union data inside the OneOfObject12 as a OneOfObject121
 func (t OneOfObject12) AsOneOfObject121() (OneOfObject121, error) {
 	var body OneOfObject121
 	err := json.Unmarshal(t.union, &body)
 	return body, err
 }
 
+// FromOneOfObject121 overwrites any union data inside the OneOfObject12 as the provided OneOfObject121
 func (t *OneOfObject12) FromOneOfObject121(v OneOfObject121) error {
 	b, err := json.Marshal(v)
 	t.union = b
 	return err
 }
 
+// MergeOneOfObject121 performs a merge with any union data inside the OneOfObject12, using the provided OneOfObject121
+func (t *OneOfObject12) MergeOneOfObject121(v OneOfObject121) error {
+	b, err := json.Marshal(v)
+	if err != nil {
+		return err
+	}
+
+	merged, err := runtime.JsonMerge(b, t.union)
+	t.union = merged
+	return err
+}
+
+// AsOneOfVariant3 returns the union data inside the OneOfObject12 as a OneOfVariant3
 func (t OneOfObject12) AsOneOfVariant3() (OneOfVariant3, error) {
 	var body OneOfVariant3
 	err := json.Unmarshal(t.union, &body)
 	return body, err
 }
 
+// FromOneOfVariant3 overwrites any union data inside the OneOfObject12 as the provided OneOfVariant3
 func (t *OneOfObject12) FromOneOfVariant3(v OneOfVariant3) error {
 	b, err := json.Marshal(v)
 	t.union = b
 	return err
 }
 
+// MergeOneOfVariant3 performs a merge with any union data inside the OneOfObject12, using the provided OneOfVariant3
+func (t *OneOfObject12) MergeOneOfVariant3(v OneOfVariant3) error {
+	b, err := json.Marshal(v)
+	if err != nil {
+		return err
+	}
+
+	merged, err := runtime.JsonMerge(b, t.union)
+	t.union = merged
+	return err
+}
+
+// AsOneOfVariant4 returns the union data inside the OneOfObject12 as a OneOfVariant4
 func (t OneOfObject12) AsOneOfVariant4() (OneOfVariant4, error) {
 	var body OneOfVariant4
 	err := json.Unmarshal(t.union, &body)
 	return body, err
 }
 
+// FromOneOfVariant4 overwrites any union data inside the OneOfObject12 as the provided OneOfVariant4
 func (t *OneOfObject12) FromOneOfVariant4(v OneOfVariant4) error {
 	b, err := json.Marshal(v)
 	t.union = b
 	return err
 }
 
+// MergeOneOfVariant4 performs a merge with any union data inside the OneOfObject12, using the provided OneOfVariant4
+func (t *OneOfObject12) MergeOneOfVariant4(v OneOfVariant4) error {
+	b, err := json.Marshal(v)
+	if err != nil {
+		return err
+	}
+
+	merged, err := runtime.JsonMerge(b, t.union)
+	t.union = merged
+	return err
+}
+
 func (t OneOfObject12) MarshalJSON() ([]byte, error) {
 	b, err := t.union.MarshalJSON()
 	return b, err
@@ -1041,42 +1242,84 @@ func (t *OneOfObject12) UnmarshalJSON(b []byte) error {
 	return err
 }
 
+// AsOneOfObject20 returns the union data inside the OneOfObject2 as a OneOfObject20
 func (t OneOfObject2) AsOneOfObject20() (OneOfObject20, error) {
 	var body OneOfObject20
 	err := json.Unmarshal(t.union, &body)
 	return body, err
 }
 
+// FromOneOfObject20 overwrites any union data inside the OneOfObject2 as the provided OneOfObject20
 func (t *OneOfObject2) FromOneOfObject20(v OneOfObject20) error {
 	b, err := json.Marshal(v)
 	t.union = b
 	return err
 }
 
+// MergeOneOfObject20 performs a merge with any union data inside the OneOfObject2, using the provided OneOfObject20
+func (t *OneOfObject2) MergeOneOfObject20(v OneOfObject20) error {
+	b, err := json.Marshal(v)
+	if err != nil {
+		return err
+	}
+
+	merged, err := runtime.JsonMerge(b, t.union)
+	t.union = merged
+	return err
+}
+
+// AsOneOfObject21 returns the union data inside the OneOfObject2 as a OneOfObject21
 func (t OneOfObject2) AsOneOfObject21() (OneOfObject21, error) {
 	var body OneOfObject21
 	err := json.Unmarshal(t.union, &body)
 	return body, err
 }
 
+// FromOneOfObject21 overwrites any union data inside the OneOfObject2 as the provided OneOfObject21
 func (t *OneOfObject2) FromOneOfObject21(v OneOfObject21) error {
 	b, err := json.Marshal(v)
 	t.union = b
 	return err
 }
 
+// MergeOneOfObject21 performs a merge with any union data inside the OneOfObject2, using the provided OneOfObject21
+func (t *OneOfObject2) MergeOneOfObject21(v OneOfObject21) error {
+	b, err := json.Marshal(v)
+	if err != nil {
+		return err
+	}
+
+	merged, err := runtime.JsonMerge(b, t.union)
+	t.union = merged
+	return err
+}
+
+// AsOneOfObject22 returns the union data inside the OneOfObject2 as a OneOfObject22
 func (t OneOfObject2) AsOneOfObject22() (OneOfObject22, error) {
 	var body OneOfObject22
 	err := json.Unmarshal(t.union, &body)
 	return body, err
 }
 
+// FromOneOfObject22 overwrites any union data inside the OneOfObject2 as the provided OneOfObject22
 func (t *OneOfObject2) FromOneOfObject22(v OneOfObject22) error {
 	b, err := json.Marshal(v)
 	t.union = b
 	return err
 }
 
+// MergeOneOfObject22 performs a merge with any union data inside the OneOfObject2, using the provided OneOfObject22
+func (t *OneOfObject2) MergeOneOfObject22(v OneOfObject22) error {
+	b, err := json.Marshal(v)
+	if err != nil {
+		return err
+	}
+
+	merged, err := runtime.JsonMerge(b, t.union)
+	t.union = merged
+	return err
+}
+
 func (t OneOfObject2) MarshalJSON() ([]byte, error) {
 	b, err := t.union.MarshalJSON()
 	return b, err
@@ -1087,42 +1330,84 @@ func (t *OneOfObject2) UnmarshalJSON(b []byte) error {
 	return err
 }
 
+// AsOneOfVariant1 returns the union data inside the OneOfObject3_Union as a OneOfVariant1
 func (t OneOfObject3_Union) AsOneOfVariant1() (OneOfVariant1, error) {
 	var body OneOfVariant1
 	err := json.Unmarshal(t.union, &body)
 	return body, err
 }
 
+// FromOneOfVariant1 overwrites any union data inside the OneOfObject3_Union as the provided OneOfVariant1
 func (t *OneOfObject3_Union) FromOneOfVariant1(v OneOfVariant1) error {
 	b, err := json.Marshal(v)
 	t.union = b
 	return err
 }
 
+// MergeOneOfVariant1 performs a merge with any union data inside the OneOfObject3_Union, using the provided OneOfVariant1
+func (t *OneOfObject3_Union) MergeOneOfVariant1(v OneOfVariant1) error {
+	b, err := json.Marshal(v)
+	if err != nil {
+		return err
+	}
+
+	merged, err := runtime.JsonMerge(b, t.union)
+	t.union = merged
+	return err
+}
+
+// AsOneOfVariant2 returns the union data inside the OneOfObject3_Union as a OneOfVariant2
 func (t OneOfObject3_Union) AsOneOfVariant2() (OneOfVariant2, error) {
 	var body OneOfVariant2
 	err := json.Unmarshal(t.union, &body)
 	return body, err
 }
 
+// FromOneOfVariant2 overwrites any union data inside the OneOfObject3_Union as the provided OneOfVariant2
 func (t *OneOfObject3_Union) FromOneOfVariant2(v OneOfVariant2) error {
 	b, err := json.Marshal(v)
 	t.union = b
 	return err
 }
 
+// MergeOneOfVariant2 performs a merge with any union data inside the OneOfObject3_Union, using the provided OneOfVariant2
+func (t *OneOfObject3_Union) MergeOneOfVariant2(v OneOfVariant2) error {
+	b, err := json.Marshal(v)
+	if err != nil {
+		return err
+	}
+
+	merged, err := runtime.JsonMerge(b, t.union)
+	t.union = merged
+	return err
+}
+
+// AsOneOfVariant3 returns the union data inside the OneOfObject3_Union as a OneOfVariant3
 func (t OneOfObject3_Union) AsOneOfVariant3() (OneOfVariant3, error) {
 	var body OneOfVariant3
 	err := json.Unmarshal(t.union, &body)
 	return body, err
 }
 
+// FromOneOfVariant3 overwrites any union data inside the OneOfObject3_Union as the provided OneOfVariant3
 func (t *OneOfObject3_Union) FromOneOfVariant3(v OneOfVariant3) error {
 	b, err := json.Marshal(v)
 	t.union = b
 	return err
 }
 
+// MergeOneOfVariant3 performs a merge with any union data inside the OneOfObject3_Union, using the provided OneOfVariant3
+func (t *OneOfObject3_Union) MergeOneOfVariant3(v OneOfVariant3) error {
+	b, err := json.Marshal(v)
+	if err != nil {
+		return err
+	}
+
+	merged, err := runtime.JsonMerge(b, t.union)
+	t.union = merged
+	return err
+}
+
 func (t OneOfObject3_Union) MarshalJSON() ([]byte, error) {
 	b, err := t.union.MarshalJSON()
 	return b, err
@@ -1133,51 +1418,95 @@ func (t *OneOfObject3_Union) UnmarshalJSON(b []byte) error {
 	return err
 }
 
+// AsOneOfVariant1 returns the union data inside the OneOfObject4 as a OneOfVariant1
 func (t OneOfObject4) AsOneOfVariant1() (OneOfVariant1, error) {
 	var body OneOfVariant1
 	err := json.Unmarshal(t.union, &body)
 	return body, err
 }
 
+// FromOneOfVariant1 overwrites any union data inside the OneOfObject4 as the provided OneOfVariant1
 func (t *OneOfObject4) FromOneOfVariant1(v OneOfVariant1) error {
 	b, err := json.Marshal(v)
 	t.union = b
 	return err
 }
 
+// MergeOneOfVariant1 performs a merge with any union data inside the OneOfObject4, using the provided OneOfVariant1
+func (t *OneOfObject4) MergeOneOfVariant1(v OneOfVariant1) error {
+	b, err := json.Marshal(v)
+	if err != nil {
+		return err
+	}
+
+	merged, err := runtime.JsonMerge(b, t.union)
+	t.union = merged
+	return err
+}
+
+// AsOneOfVariant2 returns the union data inside the OneOfObject4 as a OneOfVariant2
 func (t OneOfObject4) AsOneOfVariant2() (OneOfVariant2, error) {
 	var body OneOfVariant2
 	err := json.Unmarshal(t.union, &body)
 	return body, err
 }
 
+// FromOneOfVariant2 overwrites any union data inside the OneOfObject4 as the provided OneOfVariant2
 func (t *OneOfObject4) FromOneOfVariant2(v OneOfVariant2) error {
 	b, err := json.Marshal(v)
 	t.union = b
 	return err
 }
 
+// MergeOneOfVariant2 performs a merge with any union data inside the OneOfObject4, using the provided OneOfVariant2
+func (t *OneOfObject4) MergeOneOfVariant2(v OneOfVariant2) error {
+	b, err := json.Marshal(v)
+	if err != nil {
+		return err
+	}
+
+	merged, err := runtime.JsonMerge(b, t.union)
+	t.union = merged
+	return err
+}
+
+// AsOneOfVariant3 returns the union data inside the OneOfObject4 as a OneOfVariant3
 func (t OneOfObject4) AsOneOfVariant3() (OneOfVariant3, error) {
 	var body OneOfVariant3
 	err := json.Unmarshal(t.union, &body)
 	return body, err
 }
 
+// FromOneOfVariant3 overwrites any union data inside the OneOfObject4 as the provided OneOfVariant3
 func (t *OneOfObject4) FromOneOfVariant3(v OneOfVariant3) error {
 	b, err := json.Marshal(v)
 	t.union = b
 	return err
 }
 
+// MergeOneOfVariant3 performs a merge with any union data inside the OneOfObject4, using the provided OneOfVariant3
+func (t *OneOfObject4) MergeOneOfVariant3(v OneOfVariant3) error {
+	b, err := json.Marshal(v)
+	if err != nil {
+		return err
+	}
+
+	merged, err := runtime.JsonMerge(b, t.union)
+	t.union = merged
+	return err
+}
+
 func (t OneOfObject4) MarshalJSON() ([]byte, error) {
 	b, err := t.union.MarshalJSON()
 	if err != nil {
 		return nil, err
 	}
 	object := make(map[string]json.RawMessage)
-	err = json.Unmarshal(b, &object)
-	if err != nil {
-		return nil, err
+	if t.union != nil {
+		err = json.Unmarshal(b, &object)
+		if err != nil {
+			return nil, err
+		}
 	}
 
 	object["fixedProperty"], err = json.Marshal(t.FixedProperty)
@@ -1209,30 +1538,58 @@ func (t *OneOfObject4) UnmarshalJSON(b []byte) error {
 	return err
 }
 
+// AsOneOfVariant4 returns the union data inside the OneOfObject5 as a OneOfVariant4
 func (t OneOfObject5) AsOneOfVariant4() (OneOfVariant4, error) {
 	var body OneOfVariant4
 	err := json.Unmarshal(t.union, &body)
 	return body, err
 }
 
+// FromOneOfVariant4 overwrites any union data inside the OneOfObject5 as the provided OneOfVariant4
 func (t *OneOfObject5) FromOneOfVariant4(v OneOfVariant4) error {
 	b, err := json.Marshal(v)
 	t.union = b
 	return err
 }
 
+// MergeOneOfVariant4 performs a merge with any union data inside the OneOfObject5, using the provided OneOfVariant4
+func (t *OneOfObject5) MergeOneOfVariant4(v OneOfVariant4) error {
+	b, err := json.Marshal(v)
+	if err != nil {
+		return err
+	}
+
+	merged, err := runtime.JsonMerge(b, t.union)
+	t.union = merged
+	return err
+}
+
+// AsOneOfVariant5 returns the union data inside the OneOfObject5 as a OneOfVariant5
 func (t OneOfObject5) AsOneOfVariant5() (OneOfVariant5, error) {
 	var body OneOfVariant5
 	err := json.Unmarshal(t.union, &body)
 	return body, err
 }
 
+// FromOneOfVariant5 overwrites any union data inside the OneOfObject5 as the provided OneOfVariant5
 func (t *OneOfObject5) FromOneOfVariant5(v OneOfVariant5) error {
 	b, err := json.Marshal(v)
 	t.union = b
 	return err
 }
 
+// MergeOneOfVariant5 performs a merge with any union data inside the OneOfObject5, using the provided OneOfVariant5
+func (t *OneOfObject5) MergeOneOfVariant5(v OneOfVariant5) error {
+	b, err := json.Marshal(v)
+	if err != nil {
+		return err
+	}
+
+	merged, err := runtime.JsonMerge(b, t.union)
+	t.union = merged
+	return err
+}
+
 func (t OneOfObject5) Discriminator() (string, error) {
 	var discriminator struct {
 		Discriminator string `json:"discriminator"`
@@ -1251,12 +1608,14 @@ func (t *OneOfObject5) UnmarshalJSON(b []byte) error {
 	return err
 }
 
+// AsOneOfVariant4 returns the union data inside the OneOfObject6 as a OneOfVariant4
 func (t OneOfObject6) AsOneOfVariant4() (OneOfVariant4, error) {
 	var body OneOfVariant4
 	err := json.Unmarshal(t.union, &body)
 	return body, err
 }
 
+// FromOneOfVariant4 overwrites any union data inside the OneOfObject6 as the provided OneOfVariant4
 func (t *OneOfObject6) FromOneOfVariant4(v OneOfVariant4) error {
 	v.Discriminator = "v4"
 	b, err := json.Marshal(v)
@@ -1264,12 +1623,27 @@ func (t *OneOfObject6) FromOneOfVariant4(v OneOfVariant4) error {
 	return err
 }
 
+// MergeOneOfVariant4 performs a merge with any union data inside the OneOfObject6, using the provided OneOfVariant4
+func (t *OneOfObject6) MergeOneOfVariant4(v OneOfVariant4) error {
+	v.Discriminator = "v4"
+	b, err := json.Marshal(v)
+	if err != nil {
+		return err
+	}
+
+	merged, err := runtime.JsonMerge(b, t.union)
+	t.union = merged
+	return err
+}
+
+// AsOneOfVariant5 returns the union data inside the OneOfObject6 as a OneOfVariant5
 func (t OneOfObject6) AsOneOfVariant5() (OneOfVariant5, error) {
 	var body OneOfVariant5
 	err := json.Unmarshal(t.union, &body)
 	return body, err
 }
 
+// FromOneOfVariant5 overwrites any union data inside the OneOfObject6 as the provided OneOfVariant5
 func (t *OneOfObject6) FromOneOfVariant5(v OneOfVariant5) error {
 	v.Discriminator = "v5"
 	b, err := json.Marshal(v)
@@ -1277,6 +1651,19 @@ func (t *OneOfObject6) FromOneOfVariant5(v OneOfVariant5) error {
 	return err
 }
 
+// MergeOneOfVariant5 performs a merge with any union data inside the OneOfObject6, using the provided OneOfVariant5
+func (t *OneOfObject6) MergeOneOfVariant5(v OneOfVariant5) error {
+	v.Discriminator = "v5"
+	b, err := json.Marshal(v)
+	if err != nil {
+		return err
+	}
+
+	merged, err := runtime.JsonMerge(b, t.union)
+	t.union = merged
+	return err
+}
+
 func (t OneOfObject6) Discriminator() (string, error) {
 	var discriminator struct {
 		Discriminator string `json:"discriminator"`
@@ -1310,30 +1697,58 @@ func (t *OneOfObject6) UnmarshalJSON(b []byte) error {
 	return err
 }
 
+// AsOneOfVariant1 returns the union data inside the OneOfObject7_Item as a OneOfVariant1
 func (t OneOfObject7_Item) AsOneOfVariant1() (OneOfVariant1, error) {
 	var body OneOfVariant1
 	err := json.Unmarshal(t.union, &body)
 	return body, err
 }
 
+// FromOneOfVariant1 overwrites any union data inside the OneOfObject7_Item as the provided OneOfVariant1
 func (t *OneOfObject7_Item) FromOneOfVariant1(v OneOfVariant1) error {
 	b, err := json.Marshal(v)
 	t.union = b
 	return err
 }
 
+// MergeOneOfVariant1 performs a merge with any union data inside the OneOfObject7_Item, using the provided OneOfVariant1
+func (t *OneOfObject7_Item) MergeOneOfVariant1(v OneOfVariant1) error {
+	b, err := json.Marshal(v)
+	if err != nil {
+		return err
+	}
+
+	merged, err := runtime.JsonMerge(b, t.union)
+	t.union = merged
+	return err
+}
+
+// AsOneOfVariant2 returns the union data inside the OneOfObject7_Item as a OneOfVariant2
 func (t OneOfObject7_Item) AsOneOfVariant2() (OneOfVariant2, error) {
 	var body OneOfVariant2
 	err := json.Unmarshal(t.union, &body)
 	return body, err
 }
 
+// FromOneOfVariant2 overwrites any union data inside the OneOfObject7_Item as the provided OneOfVariant2
 func (t *OneOfObject7_Item) FromOneOfVariant2(v OneOfVariant2) error {
 	b, err := json.Marshal(v)
 	t.union = b
 	return err
 }
 
+// MergeOneOfVariant2 performs a merge with any union data inside the OneOfObject7_Item, using the provided OneOfVariant2
+func (t *OneOfObject7_Item) MergeOneOfVariant2(v OneOfVariant2) error {
+	b, err := json.Marshal(v)
+	if err != nil {
+		return err
+	}
+
+	merged, err := runtime.JsonMerge(b, t.union)
+	t.union = merged
+	return err
+}
+
 func (t OneOfObject7_Item) MarshalJSON() ([]byte, error) {
 	b, err := t.union.MarshalJSON()
 	return b, err
@@ -1344,39 +1759,69 @@ func (t *OneOfObject7_Item) UnmarshalJSON(b []byte) error {
 	return err
 }
 
+// AsOneOfVariant1 returns the union data inside the OneOfObject8 as a OneOfVariant1
 func (t OneOfObject8) AsOneOfVariant1() (OneOfVariant1, error) {
 	var body OneOfVariant1
 	err := json.Unmarshal(t.union, &body)
 	return body, err
 }
 
+// FromOneOfVariant1 overwrites any union data inside the OneOfObject8 as the provided OneOfVariant1
 func (t *OneOfObject8) FromOneOfVariant1(v OneOfVariant1) error {
 	b, err := json.Marshal(v)
 	t.union = b
 	return err
 }
 
+// MergeOneOfVariant1 performs a merge with any union data inside the OneOfObject8, using the provided OneOfVariant1
+func (t *OneOfObject8) MergeOneOfVariant1(v OneOfVariant1) error {
+	b, err := json.Marshal(v)
+	if err != nil {
+		return err
+	}
+
+	merged, err := runtime.JsonMerge(b, t.union)
+	t.union = merged
+	return err
+}
+
+// AsOneOfVariant2 returns the union data inside the OneOfObject8 as a OneOfVariant2
 func (t OneOfObject8) AsOneOfVariant2() (OneOfVariant2, error) {
 	var body OneOfVariant2
 	err := json.Unmarshal(t.union, &body)
 	return body, err
 }
 
+// FromOneOfVariant2 overwrites any union data inside the OneOfObject8 as the provided OneOfVariant2
 func (t *OneOfObject8) FromOneOfVariant2(v OneOfVariant2) error {
 	b, err := json.Marshal(v)
 	t.union = b
 	return err
 }
 
+// MergeOneOfVariant2 performs a merge with any union data inside the OneOfObject8, using the provided OneOfVariant2
+func (t *OneOfObject8) MergeOneOfVariant2(v OneOfVariant2) error {
+	b, err := json.Marshal(v)
+	if err != nil {
+		return err
+	}
+
+	merged, err := runtime.JsonMerge(b, t.union)
+	t.union = merged
+	return err
+}
+
 func (t OneOfObject8) MarshalJSON() ([]byte, error) {
 	b, err := t.union.MarshalJSON()
 	if err != nil {
 		return nil, err
 	}
 	object := make(map[string]json.RawMessage)
-	err = json.Unmarshal(b, &object)
-	if err != nil {
-		return nil, err
+	if t.union != nil {
+		err = json.Unmarshal(b, &object)
+		if err != nil {
+			return nil, err
+		}
 	}
 
 	object["fixed"], err = json.Marshal(t.Fixed)
@@ -1408,12 +1853,14 @@ func (t *OneOfObject8) UnmarshalJSON(b []byte) error {
 	return err
 }
 
+// AsOneOfVariant1 returns the union data inside the OneOfObject9 as a OneOfVariant1
 func (t OneOfObject9) AsOneOfVariant1() (OneOfVariant1, error) {
 	var body OneOfVariant1
 	err := json.Unmarshal(t.union, &body)
 	return body, err
 }
 
+// FromOneOfVariant1 overwrites any union data inside the OneOfObject9 as the provided OneOfVariant1
 func (t *OneOfObject9) FromOneOfVariant1(v OneOfVariant1) error {
 	t.Type = "v1"
 
@@ -1422,12 +1869,28 @@ func (t *OneOfObject9) FromOneOfVariant1(v OneOfVariant1) error {
 	return err
 }
 
+// MergeOneOfVariant1 performs a merge with any union data inside the OneOfObject9, using the provided OneOfVariant1
+func (t *OneOfObject9) MergeOneOfVariant1(v OneOfVariant1) error {
+	t.Type = "v1"
+
+	b, err := json.Marshal(v)
+	if err != nil {
+		return err
+	}
+
+	merged, err := runtime.JsonMerge(b, t.union)
+	t.union = merged
+	return err
+}
+
+// AsOneOfVariant6 returns the union data inside the OneOfObject9 as a OneOfVariant6
 func (t OneOfObject9) AsOneOfVariant6() (OneOfVariant6, error) {
 	var body OneOfVariant6
 	err := json.Unmarshal(t.union, &body)
 	return body, err
 }
 
+// FromOneOfVariant6 overwrites any union data inside the OneOfObject9 as the provided OneOfVariant6
 func (t *OneOfObject9) FromOneOfVariant6(v OneOfVariant6) error {
 	t.Type = "v6"
 
@@ -1436,6 +1899,20 @@ func (t *OneOfObject9) FromOneOfVariant6(v OneOfVariant6) error {
 	return err
 }
 
+// MergeOneOfVariant6 performs a merge with any union data inside the OneOfObject9, using the provided OneOfVariant6
+func (t *OneOfObject9) MergeOneOfVariant6(v OneOfVariant6) error {
+	t.Type = "v6"
+
+	b, err := json.Marshal(v)
+	if err != nil {
+		return err
+	}
+
+	merged, err := runtime.JsonMerge(b, t.union)
+	t.union = merged
+	return err
+}
+
 func (t OneOfObject9) Discriminator() (string, error) {
 	var discriminator struct {
 		Discriminator string `json:"type"`
@@ -1465,9 +1942,11 @@ func (t OneOfObject9) MarshalJSON() ([]byte, error) {
 		return nil, err
 	}
 	object := make(map[string]json.RawMessage)
-	err = json.Unmarshal(b, &object)
-	if err != nil {
-		return nil, err
+	if t.union != nil {
+		err = json.Unmarshal(b, &object)
+		if err != nil {
+			return nil, err
+		}
 	}
 
 	object["type"], err = json.Marshal(t.Type)
diff --git a/internal/test/components/components.yaml b/internal/test/components/components.yaml
index f5d6441..f49173a 100644
--- a/internal/test/components/components.yaml
+++ b/internal/test/components/components.yaml
@@ -429,6 +429,7 @@ components:
         - '*'
         - '5'
         - '&'
+        - '%'
         - ''
     RenameMe:
       description: This schema should be renamed via x-go-name when generating
diff --git a/internal/test/components/components_test.go b/internal/test/components/components_test.go
index b4f8933..bcb34d7 100644
--- a/internal/test/components/components_test.go
+++ b/internal/test/components/components_test.go
@@ -202,3 +202,13 @@ func TestAnyOf(t *testing.T) {
 	assert.NoError(t, err)
 	assert.Equal(t, OneOfVariant5{Discriminator: "all", Id: 456}, v5)
 }
+
+func TestMarshalWhenNoUnionValueSet(t *testing.T) {
+	const expected = `{"one":null,"three":null,"two":null}`
+
+	var dst OneOfObject10
+
+	bytes, err := dst.MarshalJSON()
+	assert.Nil(t, err)
+	assert.Equal(t, expected, string(bytes))
+}
diff --git a/internal/test/issues/issue-312/issue.gen.go b/internal/test/issues/issue-312/issue.gen.go
index 3f4c918..a2553a1 100644
--- a/internal/test/issues/issue-312/issue.gen.go
+++ b/internal/test/issues/issue-312/issue.gen.go
@@ -24,22 +24,22 @@ import (
 
 // Error defines model for Error.
 type Error struct {
-	// Error code
+	// Code Error code
 	Code int32 `json:"code"`
 
-	// Error message
+	// Message Error message
 	Message string `json:"message"`
 }
 
 // Pet defines model for Pet.
 type Pet struct {
-	// The name of the pet.
+	// Name The name of the pet.
 	Name string `json:"name"`
 }
 
 // PetNames defines model for PetNames.
 type PetNames struct {
-	// The names of the pets.
+	// Names The names of the pets.
 	Names []string `json:"names"`
 }
 
diff --git a/internal/test/issues/issue-grab_import_names/issue.gen.go b/internal/test/issues/issue-grab_import_names/issue.gen.go
index 95d6e13..0f0d27f 100644
--- a/internal/test/issues/issue-grab_import_names/issue.gen.go
+++ b/internal/test/issues/issue-grab_import_names/issue.gen.go
@@ -23,10 +23,10 @@ import (
 
 // GetFooParams defines parameters for GetFoo.
 type GetFooParams struct {
-	// base64. bytes. chi. context. echo. errors. fmt. gzip. http. io. ioutil. json. openapi3.
+	// Foo base64. bytes. chi. context. echo. errors. fmt. gzip. http. io. ioutil. json. openapi3.
 	Foo *string `json:"Foo,omitempty"`
 
-	// openapi_types. path. runtime. strings. time.Duration time.Time url. xml. yaml.
+	// Bar openapi_types. path. runtime. strings. time.Duration time.Time url. xml. yaml.
 	Bar *string `json:"Bar,omitempty"`
 }
 
diff --git a/internal/test/issues/issue-illegal_enum_names/issue.gen.go b/internal/test/issues/issue-illegal_enum_names/issue.gen.go
index cf58178..35dcbe1 100644
--- a/internal/test/issues/issue-illegal_enum_names/issue.gen.go
+++ b/internal/test/issues/issue-illegal_enum_names/issue.gen.go
@@ -23,6 +23,7 @@ import (
 // Defines values for Bar.
 const (
 	BarBar     Bar = "Bar"
+	BarEmpty   Bar = ""
 	BarFoo     Bar = "Foo"
 	BarFoo1    Bar = " Foo"
 	BarFoo2    Bar = " Foo "
@@ -313,10 +314,10 @@ func RegisterHandlersWithBaseURL(router EchoRouter, si ServerInterface, baseURL
 var swaggerSpec = []string{
 
 	"H4sIAAAAAAAC/0xQQU4DMQz8SjVwDNml3HLkUMQbEKqirbcN6tpRYpCqKn9HzkIhl5kkHtszV0yyZGFi",
-	"rQhX1OlES+z0ORYD4s8F4Q07Ebj+6IxvbuxhZY//CzbrxWADh/1OZG81eHfQSyYEVC2Jj2itOSSexWZp",
-	"0rP9ee/h8EWlJmEEjH70I5qDZOKYEwKe/Oi3cMhRT33dYZbe40hqIJlK1CT8ekDAC+m6UaGahSt1yXYc",
-	"DSZhJe6qmPM5TV03fFSb/RuJsaS0dOF9oRkBd8NfeMNPcoMF0G4uYynxspo8UJ1KyrpaMoutn+8AAAD/",
-	"/y6OlsyDAQAA",
+	"rQhX1OlES+z0ORYD4s8F4Q1w2InA9ffONzf2sLLH/wWb9WKwgcN+J7K3Grw76CUTAqqWxEe01hwSz2Lj",
+	"NOnZ/rz3cPiiUpMwAkY/+hHNQTJxzAkBT370WzjkqKe+8TBL73EkNZBMJWoSfj0g4IV03ahQzcKVumQ7",
+	"jgaTsBJ3Vcz5nKauGz6qzf5NxVhSWrrwvtCMgLvhL7/hJ7zBAmg3l7GUeFlNHqhOJWVdLZnF1s93AAAA",
+	"//9U8KAOhgEAAA==",
 }
 
 // GetSwagger returns the content of the embedded swagger specification file
diff --git a/internal/test/issues/issue-illegal_enum_names/issue_test.go b/internal/test/issues/issue-illegal_enum_names/issue_test.go
index 8c40e09..c924eaa 100644
--- a/internal/test/issues/issue-illegal_enum_names/issue_test.go
+++ b/internal/test/issues/issue-illegal_enum_names/issue_test.go
@@ -47,6 +47,7 @@ func TestIllegalEnumNames(t *testing.T) {
 		}
 	}
 
+	require.Equal(t, `""`, constDefs["BarEmpty"])
 	require.Equal(t, `"Bar"`, constDefs["BarBar"])
 	require.Equal(t, `"Foo"`, constDefs["BarFoo"])
 	require.Equal(t, `"Foo Bar"`, constDefs["BarFooBar"])
diff --git a/internal/test/issues/issue-illegal_enum_names/spec.yaml b/internal/test/issues/issue-illegal_enum_names/spec.yaml
index cf3fc78..d222a57 100644
--- a/internal/test/issues/issue-illegal_enum_names/spec.yaml
+++ b/internal/test/issues/issue-illegal_enum_names/spec.yaml
@@ -22,6 +22,7 @@ components:
     Bar:
       type: string
       enum:
+        - ''
         - Foo
         - Bar
         - Foo Bar
diff --git a/internal/test/parameters/parameters.gen.go b/internal/test/parameters/parameters.gen.go
index 2b3c7a3..9be420d 100644
--- a/internal/test/parameters/parameters.gen.go
+++ b/internal/test/parameters/parameters.gen.go
@@ -42,34 +42,34 @@ type Object struct {
 
 // GetCookieParams defines parameters for GetCookie.
 type GetCookieParams struct {
-	// primitive
+	// P primitive
 	P *int32 `form:"p,omitempty" json:"p,omitempty"`
 
-	// primitive
+	// Ep primitive
 	Ep *int32 `form:"ep,omitempty" json:"ep,omitempty"`
 
-	// exploded array
+	// Ea exploded array
 	Ea *[]int32 `form:"ea,omitempty" json:"ea,omitempty"`
 
-	// array
+	// A array
 	A *[]int32 `form:"a,omitempty" json:"a,omitempty"`
 
-	// exploded object
+	// Eo exploded object
 	Eo *Object `form:"eo,omitempty" json:"eo,omitempty"`
 
-	// object
+	// O object
 	O *Object `form:"o,omitempty" json:"o,omitempty"`
 
-	// complex object
+	// Co complex object
 	Co *ComplexObject `form:"co,omitempty" json:"co,omitempty"`
 
-	// name starting with number
+	// N1s name starting with number
 	N1s *string `form:"1s,omitempty" json:"1s,omitempty"`
 }
 
 // EnumParamsParams defines parameters for EnumParams.
 type EnumParamsParams struct {
-	// Parameter with enum values
+	// EnumPathParam Parameter with enum values
 	EnumPathParam *EnumParamsParamsEnumPathParam `form:"enumPathParam,omitempty" json:"enumPathParam,omitempty"`
 }
 
@@ -78,64 +78,64 @@ type EnumParamsParamsEnumPathParam int32
 
 // GetHeaderParams defines parameters for GetHeader.
 type GetHeaderParams struct {
-	// primitive
+	// XPrimitive primitive
 	XPrimitive *int32 `json:"X-Primitive,omitempty"`
 
-	// primitive
+	// XPrimitiveExploded primitive
 	XPrimitiveExploded *int32 `json:"X-Primitive-Exploded,omitempty"`
 
-	// exploded array
+	// XArrayExploded exploded array
 	XArrayExploded *[]int32 `json:"X-Array-Exploded,omitempty"`
 
-	// array
+	// XArray array
 	XArray *[]int32 `json:"X-Array,omitempty"`
 
-	// exploded object
+	// XObjectExploded exploded object
 	XObjectExploded *Object `json:"X-Object-Exploded,omitempty"`
 
-	// object
+	// XObject object
 	XObject *Object `json:"X-Object,omitempty"`
 
-	// complex object
+	// XComplexObject complex object
 	XComplexObject *ComplexObject `json:"X-Complex-Object,omitempty"`
 
-	// name starting with number
+	// N1StartingWithNumber name starting with number
 	N1StartingWithNumber *string `json:"1-Starting-With-Number,omitempty"`
 }
 
 // GetDeepObjectParams defines parameters for GetDeepObject.
 type GetDeepObjectParams struct {
-	// deep object
+	// DeepObj deep object
 	DeepObj ComplexObject `json:"deepObj"`
 }
 
 // GetQueryFormParams defines parameters for GetQueryForm.
 type GetQueryFormParams struct {
-	// exploded array
+	// Ea exploded array
 	Ea *[]int32 `form:"ea,omitempty" json:"ea,omitempty"`
 
-	// array
+	// A array
 	A *[]int32 `form:"a,omitempty" json:"a,omitempty"`
 
-	// exploded object
+	// Eo exploded object
 	Eo *Object `form:"eo,omitempty" json:"eo,omitempty"`
 
-	// object
+	// O object
 	O *Object `form:"o,omitempty" json:"o,omitempty"`
 
-	// exploded primitive
+	// Ep exploded primitive
 	Ep *int32 `form:"ep,omitempty" json:"ep,omitempty"`
 
-	// primitive
+	// P primitive
 	P *int32 `form:"p,omitempty" json:"p,omitempty"`
 
-	// primitive string
+	// Ps primitive string
 	Ps *string `form:"ps,omitempty" json:"ps,omitempty"`
 
-	// complex object
+	// Co complex object
 	Co *ComplexObject `form:"co,omitempty" json:"co,omitempty"`
 
-	// name starting with number
+	// N1s name starting with number
 	N1s *string `form:"1s,omitempty" json:"1s,omitempty"`
 }
 
diff --git a/internal/test/parameters/parameters_test.go b/internal/test/parameters/parameters_test.go
index f999ac5..b0fe6b1 100644
--- a/internal/test/parameters/parameters_test.go
+++ b/internal/test/parameters/parameters_test.go
@@ -236,6 +236,11 @@ func (t *testServer) GetCookie(ctx echo.Context, params GetCookieParams) error {
 	return nil
 }
 
+// (GET /enums)
+func (t *testServer) EnumParams(ctx echo.Context, params EnumParamsParams) error {
+	return ctx.NoContent(http.StatusNotImplemented)
+}
+
 func TestParameterBinding(t *testing.T) {
 	var ts testServer
 	e := echo.New()
diff --git a/internal/test/schemas/schemas.gen.go b/internal/test/schemas/schemas.gen.go
index c803061..774512e 100644
--- a/internal/test/schemas/schemas.gen.go
+++ b/internal/test/schemas/schemas.gen.go
@@ -35,13 +35,13 @@ const (
 	Second EnumInObjInArrayVal = "second"
 )
 
-// This schema name starts with a number
+// N5StartsWithNumber This schema name starts with a number
 type N5StartsWithNumber = map[string]interface{}
 
 // AnyType1 defines model for AnyType1.
 type AnyType1 = interface{}
 
-// AnyType2 represents any type.
+// AnyType2 AnyType2 represents any type.
 //
 // This should be an interface{}
 type AnyType2 = interface{}
@@ -664,7 +664,7 @@ type EnsureEverythingIsReferencedResponse struct {
 	JSON200      *struct {
 		AnyType1 *AnyType1 `json:"anyType1,omitempty"`
 
-		// AnyType2 represents any type.
+		// AnyType2 AnyType2 represents any type.
 		//
 		// This should be an interface{}
 		AnyType2         *AnyType2         `json:"anyType2,omitempty"`
@@ -946,7 +946,7 @@ func ParseEnsureEverythingIsReferencedResponse(rsp *http.Response) (*EnsureEvery
 		var dest struct {
 			AnyType1 *AnyType1 `json:"anyType1,omitempty"`
 
-			// AnyType2 represents any type.
+			// AnyType2 AnyType2 represents any type.
 			//
 			// This should be an interface{}
 			AnyType2         *AnyType2         `json:"anyType2,omitempty"`
diff --git a/internal/test/server/server.gen.go b/internal/test/server/server.gen.go
index bd747ca..d676d16 100644
--- a/internal/test/server/server.gen.go
+++ b/internal/test/server/server.gen.go
@@ -93,13 +93,13 @@ type SimpleResponse struct {
 
 // GetWithArgsParams defines parameters for GetWithArgs.
 type GetWithArgsParams struct {
-	// An optional query argument
+	// OptionalArgument An optional query argument
 	OptionalArgument *int64 `form:"optional_argument,omitempty" json:"optional_argument,omitempty"`
 
-	// An optional query argument
+	// RequiredArgument An optional query argument
 	RequiredArgument int64 `form:"required_argument" json:"required_argument"`
 
-	// An optional query argument
+	// HeaderArgument An optional query argument
 	HeaderArgument *int32 `json:"header_argument,omitempty"`
 }
 
@@ -108,7 +108,7 @@ type GetWithContentTypeParamsContentType string
 
 // CreateResource2Params defines parameters for CreateResource2.
 type CreateResource2Params struct {
-	// Some query argument
+	// InlineQueryArgument Some query argument
 	InlineQueryArgument *int `form:"inline_query_argument,omitempty" json:"inline_query_argument,omitempty"`
 }
 
@@ -211,9 +211,6 @@ func (siw *ServerInterfaceWrapper) GetWithArgs(w http.ResponseWriter, r *http.Re
 	var params GetWithArgsParams
 
 	// ------------- Optional query parameter "optional_argument" -------------
-	if paramValue := r.URL.Query().Get("optional_argument"); paramValue != "" {
-
-	}
 
 	err = runtime.BindQueryParameter("form", true, false, "optional_argument", r.URL.Query(), &params.OptionalArgument)
 	if err != nil {
@@ -222,6 +219,7 @@ func (siw *ServerInterfaceWrapper) GetWithArgs(w http.ResponseWriter, r *http.Re
 	}
 
 	// ------------- Required query parameter "required_argument" -------------
+
 	if paramValue := r.URL.Query().Get("required_argument"); paramValue != "" {
 
 	} else {
@@ -388,9 +386,6 @@ func (siw *ServerInterfaceWrapper) CreateResource2(w http.ResponseWriter, r *htt
 	var params CreateResource2Params
 
 	// ------------- Optional query parameter "inline_query_argument" -------------
-	if paramValue := r.URL.Query().Get("inline_query_argument"); paramValue != "" {
-
-	}
 
 	err = runtime.BindQueryParameter("form", true, false, "inline_query_argument", r.URL.Query(), &params.InlineQueryArgument)
 	if err != nil {
diff --git a/internal/test/strict-server/chi/server.gen.go b/internal/test/strict-server/chi/server.gen.go
index 32f2692..a40b603 100644
--- a/internal/test/strict-server/chi/server.gen.go
+++ b/internal/test/strict-server/chi/server.gen.go
@@ -597,13 +597,30 @@ type StrictHandlerFunc func(ctx context.Context, w http.ResponseWriter, r *http.
 
 type StrictMiddlewareFunc func(f StrictHandlerFunc, operationID string) StrictHandlerFunc
 
+type StrictChiServerOptions struct {
+	RequestErrorHandlerFunc  func(w http.ResponseWriter, r *http.Request, err error)
+	ResponseErrorHandlerFunc func(w http.ResponseWriter, r *http.Request, err error)
+}
+
 func NewStrictHandler(ssi StrictServerInterface, middlewares []StrictMiddlewareFunc) ServerInterface {
-	return &strictHandler{ssi: ssi, middlewares: middlewares}
+	return &strictHandler{ssi: ssi, middlewares: middlewares, options: StrictChiServerOptions{
+		RequestErrorHandlerFunc: func(w http.ResponseWriter, r *http.Request, err error) {
+			http.Error(w, err.Error(), http.StatusBadRequest)
+		},
+		ResponseErrorHandlerFunc: func(w http.ResponseWriter, r *http.Request, err error) {
+			http.Error(w, err.Error(), http.StatusInternalServerError)
+		},
+	}}
+}
+
+func NewStrictHandlerWithOptions(ssi StrictServerInterface, middlewares []StrictMiddlewareFunc, options StrictChiServerOptions) ServerInterface {
+	return &strictHandler{ssi: ssi, middlewares: middlewares, options: options}
 }
 
 type strictHandler struct {
 	ssi         StrictServerInterface
 	middlewares []StrictMiddlewareFunc
+	options     StrictChiServerOptions
 }
 
 // JSONExample operation middleware
@@ -612,7 +629,7 @@ func (sh *strictHandler) JSONExample(w http.ResponseWriter, r *http.Request) {
 
 	var body JSONExampleJSONRequestBody
 	if err := json.NewDecoder(r.Body).Decode(&body); err != nil {
-		http.Error(w, "can't decode JSON body: "+err.Error(), http.StatusBadRequest)
+		sh.options.RequestErrorHandlerFunc(w, r, fmt.Errorf("can't decode JSON body: %w", err))
 		return
 	}
 	request.Body = &body
@@ -636,10 +653,10 @@ func (sh *strictHandler) JSONExample(w http.ResponseWriter, r *http.Request) {
 	case JSONExampledefaultResponse:
 		w.WriteHeader(v.StatusCode)
 	case error:
-		http.Error(w, v.Error(), http.StatusInternalServerError)
+		sh.options.ResponseErrorHandlerFunc(w, r, v)
 	case nil:
 	default:
-		http.Error(w, fmt.Sprintf("Unexpected response type: %T", v), http.StatusInternalServerError)
+		sh.options.ResponseErrorHandlerFunc(w, r, fmt.Errorf("Unexpected response type: %T", v))
 	}
 }
 
@@ -648,7 +665,7 @@ func (sh *strictHandler) MultipartExample(w http.ResponseWriter, r *http.Request
 	var request MultipartExampleRequestObject
 
 	if reader, err := r.MultipartReader(); err != nil {
-		http.Error(w, "can't decode multipart body: "+err.Error(), http.StatusBadRequest)
+		sh.options.RequestErrorHandlerFunc(w, r, fmt.Errorf("can't decode multipart body: %w", err))
 		return
 	} else {
 		request.Body = reader
@@ -670,17 +687,17 @@ func (sh *strictHandler) MultipartExample(w http.ResponseWriter, r *http.Request
 		w.WriteHeader(200)
 		defer writer.Close()
 		if err := v(writer); err != nil {
-			http.Error(w, err.Error(), http.StatusInternalServerError)
+			sh.options.ResponseErrorHandlerFunc(w, r, err)
 		}
 	case MultipartExample400Response:
 		w.WriteHeader(400)
 	case MultipartExampledefaultResponse:
 		w.WriteHeader(v.StatusCode)
 	case error:
-		http.Error(w, v.Error(), http.StatusInternalServerError)
+		sh.options.ResponseErrorHandlerFunc(w, r, v)
 	case nil:
 	default:
-		http.Error(w, fmt.Sprintf("Unexpected response type: %T", v), http.StatusInternalServerError)
+		sh.options.ResponseErrorHandlerFunc(w, r, fmt.Errorf("Unexpected response type: %T", v))
 	}
 }
 
@@ -691,19 +708,19 @@ func (sh *strictHandler) MultipleRequestAndResponseTypes(w http.ResponseWriter,
 	if strings.HasPrefix(r.Header.Get("Content-Type"), "application/json") {
 		var body MultipleRequestAndResponseTypesJSONRequestBody
 		if err := json.NewDecoder(r.Body).Decode(&body); err != nil {
-			http.Error(w, "can't decode JSON body: "+err.Error(), http.StatusBadRequest)
+			sh.options.RequestErrorHandlerFunc(w, r, fmt.Errorf("can't decode JSON body: %w", err))
 			return
 		}
 		request.JSONBody = &body
 	}
 	if strings.HasPrefix(r.Header.Get("Content-Type"), "application/x-www-form-urlencoded") {
 		if err := r.ParseForm(); err != nil {
-			http.Error(w, "can't decode formdata: "+err.Error(), http.StatusBadRequest)
+			sh.options.RequestErrorHandlerFunc(w, r, fmt.Errorf("can't decode formdata: %w", err))
 			return
 		}
 		var body MultipleRequestAndResponseTypesFormdataRequestBody
 		if err := runtime.BindForm(&body, r.Form, nil, nil); err != nil {
-			http.Error(w, "can't bind formdata: "+err.Error(), http.StatusBadRequest)
+			sh.options.RequestErrorHandlerFunc(w, r, fmt.Errorf("can't bind formdata: %w", err))
 			return
 		}
 		request.FormdataBody = &body
@@ -713,7 +730,7 @@ func (sh *strictHandler) MultipleRequestAndResponseTypes(w http.ResponseWriter,
 	}
 	if strings.HasPrefix(r.Header.Get("Content-Type"), "multipart/form-data") {
 		if reader, err := r.MultipartReader(); err != nil {
-			http.Error(w, "can't decode multipart body: "+err.Error(), http.StatusBadRequest)
+			sh.options.RequestErrorHandlerFunc(w, r, fmt.Errorf("can't decode multipart body: %w", err))
 			return
 		} else {
 			request.MultipartBody = reader
@@ -722,7 +739,7 @@ func (sh *strictHandler) MultipleRequestAndResponseTypes(w http.ResponseWriter,
 	if strings.HasPrefix(r.Header.Get("Content-Type"), "text/plain") {
 		data, err := ioutil.ReadAll(r.Body)
 		if err != nil {
-			http.Error(w, "can't read body: "+err.Error(), http.StatusBadRequest)
+			sh.options.RequestErrorHandlerFunc(w, r, fmt.Errorf("can't read body: %w", err))
 			return
 		}
 		body := MultipleRequestAndResponseTypesTextRequestBody(data)
@@ -767,7 +784,7 @@ func (sh *strictHandler) MultipleRequestAndResponseTypes(w http.ResponseWriter,
 		w.WriteHeader(200)
 		defer writer.Close()
 		if err := v(writer); err != nil {
-			http.Error(w, err.Error(), http.StatusInternalServerError)
+			sh.options.ResponseErrorHandlerFunc(w, r, err)
 		}
 	case MultipleRequestAndResponseTypes200TextResponse:
 		w.Header().Set("Content-Type", "text/plain")
@@ -776,10 +793,10 @@ func (sh *strictHandler) MultipleRequestAndResponseTypes(w http.ResponseWriter,
 	case MultipleRequestAndResponseTypes400Response:
 		w.WriteHeader(400)
 	case error:
-		http.Error(w, v.Error(), http.StatusInternalServerError)
+		sh.options.ResponseErrorHandlerFunc(w, r, v)
 	case nil:
 	default:
-		http.Error(w, fmt.Sprintf("Unexpected response type: %T", v), http.StatusInternalServerError)
+		sh.options.ResponseErrorHandlerFunc(w, r, fmt.Errorf("Unexpected response type: %T", v))
 	}
 }
 
@@ -789,7 +806,7 @@ func (sh *strictHandler) ReusableResponses(w http.ResponseWriter, r *http.Reques
 
 	var body ReusableResponsesJSONRequestBody
 	if err := json.NewDecoder(r.Body).Decode(&body); err != nil {
-		http.Error(w, "can't decode JSON body: "+err.Error(), http.StatusBadRequest)
+		sh.options.RequestErrorHandlerFunc(w, r, fmt.Errorf("can't decode JSON body: %w", err))
 		return
 	}
 	request.Body = &body
@@ -815,10 +832,10 @@ func (sh *strictHandler) ReusableResponses(w http.ResponseWriter, r *http.Reques
 	case ReusableResponsesdefaultResponse:
 		w.WriteHeader(v.StatusCode)
 	case error:
-		http.Error(w, v.Error(), http.StatusInternalServerError)
+		sh.options.ResponseErrorHandlerFunc(w, r, v)
 	case nil:
 	default:
-		http.Error(w, fmt.Sprintf("Unexpected response type: %T", v), http.StatusInternalServerError)
+		sh.options.ResponseErrorHandlerFunc(w, r, fmt.Errorf("Unexpected response type: %T", v))
 	}
 }
 
@@ -828,7 +845,7 @@ func (sh *strictHandler) TextExample(w http.ResponseWriter, r *http.Request) {
 
 	data, err := ioutil.ReadAll(r.Body)
 	if err != nil {
-		http.Error(w, "can't read body: "+err.Error(), http.StatusBadRequest)
+		sh.options.RequestErrorHandlerFunc(w, r, fmt.Errorf("can't read body: %w", err))
 		return
 	}
 	body := TextExampleTextRequestBody(data)
@@ -853,10 +870,10 @@ func (sh *strictHandler) TextExample(w http.ResponseWriter, r *http.Request) {
 	case TextExampledefaultResponse:
 		w.WriteHeader(v.StatusCode)
 	case error:
-		http.Error(w, v.Error(), http.StatusInternalServerError)
+		sh.options.ResponseErrorHandlerFunc(w, r, v)
 	case nil:
 	default:
-		http.Error(w, fmt.Sprintf("Unexpected response type: %T", v), http.StatusInternalServerError)
+		sh.options.ResponseErrorHandlerFunc(w, r, fmt.Errorf("Unexpected response type: %T", v))
 	}
 }
 
@@ -891,10 +908,10 @@ func (sh *strictHandler) UnknownExample(w http.ResponseWriter, r *http.Request)
 	case UnknownExampledefaultResponse:
 		w.WriteHeader(v.StatusCode)
 	case error:
-		http.Error(w, v.Error(), http.StatusInternalServerError)
+		sh.options.ResponseErrorHandlerFunc(w, r, v)
 	case nil:
 	default:
-		http.Error(w, fmt.Sprintf("Unexpected response type: %T", v), http.StatusInternalServerError)
+		sh.options.ResponseErrorHandlerFunc(w, r, fmt.Errorf("Unexpected response type: %T", v))
 	}
 }
 
@@ -935,10 +952,10 @@ func (sh *strictHandler) UnspecifiedContentType(w http.ResponseWriter, r *http.R
 	case UnspecifiedContentTypedefaultResponse:
 		w.WriteHeader(v.StatusCode)
 	case error:
-		http.Error(w, v.Error(), http.StatusInternalServerError)
+		sh.options.ResponseErrorHandlerFunc(w, r, v)
 	case nil:
 	default:
-		http.Error(w, fmt.Sprintf("Unexpected response type: %T", v), http.StatusInternalServerError)
+		sh.options.ResponseErrorHandlerFunc(w, r, fmt.Errorf("Unexpected response type: %T", v))
 	}
 }
 
@@ -947,12 +964,12 @@ func (sh *strictHandler) URLEncodedExample(w http.ResponseWriter, r *http.Reques
 	var request URLEncodedExampleRequestObject
 
 	if err := r.ParseForm(); err != nil {
-		http.Error(w, "can't decode formdata: "+err.Error(), http.StatusBadRequest)
+		sh.options.RequestErrorHandlerFunc(w, r, fmt.Errorf("can't decode formdata: %w", err))
 		return
 	}
 	var body URLEncodedExampleFormdataRequestBody
 	if err := runtime.BindForm(&body, r.Form, nil, nil); err != nil {
-		http.Error(w, "can't bind formdata: "+err.Error(), http.StatusBadRequest)
+		sh.options.RequestErrorHandlerFunc(w, r, fmt.Errorf("can't bind formdata: %w", err))
 		return
 	}
 	request.Body = &body
@@ -980,10 +997,10 @@ func (sh *strictHandler) URLEncodedExample(w http.ResponseWriter, r *http.Reques
 	case URLEncodedExampledefaultResponse:
 		w.WriteHeader(v.StatusCode)
 	case error:
-		http.Error(w, v.Error(), http.StatusInternalServerError)
+		sh.options.ResponseErrorHandlerFunc(w, r, v)
 	case nil:
 	default:
-		http.Error(w, fmt.Sprintf("Unexpected response type: %T", v), http.StatusInternalServerError)
+		sh.options.ResponseErrorHandlerFunc(w, r, fmt.Errorf("Unexpected response type: %T", v))
 	}
 }
 
@@ -995,7 +1012,7 @@ func (sh *strictHandler) HeadersExample(w http.ResponseWriter, r *http.Request,
 
 	var body HeadersExampleJSONRequestBody
 	if err := json.NewDecoder(r.Body).Decode(&body); err != nil {
-		http.Error(w, "can't decode JSON body: "+err.Error(), http.StatusBadRequest)
+		sh.options.RequestErrorHandlerFunc(w, r, fmt.Errorf("can't decode JSON body: %w", err))
 		return
 	}
 	request.Body = &body
@@ -1021,10 +1038,10 @@ func (sh *strictHandler) HeadersExample(w http.ResponseWriter, r *http.Request,
 	case HeadersExampledefaultResponse:
 		w.WriteHeader(v.StatusCode)
 	case error:
-		http.Error(w, v.Error(), http.StatusInternalServerError)
+		sh.options.ResponseErrorHandlerFunc(w, r, v)
 	case nil:
 	default:
-		http.Error(w, fmt.Sprintf("Unexpected response type: %T", v), http.StatusInternalServerError)
+		sh.options.ResponseErrorHandlerFunc(w, r, fmt.Errorf("Unexpected response type: %T", v))
 	}
 }
 
diff --git a/pkg/codegen/codegen_test.go b/pkg/codegen/codegen_test.go
index 8d333a6..919cad6 100644
--- a/pkg/codegen/codegen_test.go
+++ b/pkg/codegen/codegen_test.go
@@ -8,6 +8,10 @@ import (
 	"net/http"
 	"testing"
 
+	"github.com/stretchr/testify/require"
+
+	"github.com/deepmap/oapi-codegen/pkg/util"
+
 	"github.com/getkin/kin-openapi/openapi3"
 	"github.com/golangci/lint-1"
 	"github.com/stretchr/testify/assert"
@@ -16,6 +20,13 @@ import (
 	examplePetstore "github.com/deepmap/oapi-codegen/examples/petstore-expanded/echo/api"
 )
 
+func checkLint(t *testing.T, filename string, code []byte) {
+	linter := new(lint.Linter)
+	problems, err := linter.Lint("test.gen.go", code)
+	assert.NoError(t, err)
+	assert.Len(t, problems, 0)
+}
+
 func TestExamplePetStoreCodeGeneration(t *testing.T) {
 
 	// Input vars for code generation:
@@ -50,7 +61,7 @@ func TestExamplePetStoreCodeGeneration(t *testing.T) {
 	assert.Contains(t, code, "func (c *Client) FindPetByID(ctx context.Context, id int64, reqEditors ...RequestEditorFn) (*http.Response, error) {")
 
 	// Check that the property comments were generated
-	assert.Contains(t, code, "// Unique id of the pet")
+	assert.Contains(t, code, "// Id Unique id of the pet")
 
 	// Check that the summary comment contains newlines
 	assert.Contains(t, code, `// Deletes a pet by ID
@@ -58,10 +69,7 @@ func TestExamplePetStoreCodeGeneration(t *testing.T) {
 `)
 
 	// Make sure the generated code is valid:
-	linter := new(lint.Linter)
-	problems, err := linter.Lint("test.gen.go", []byte(code))
-	assert.NoError(t, err)
-	assert.Len(t, problems, 0)
+	checkLint(t, "test.gen.go", []byte(code))
 }
 
 func TestExamplePetStoreCodeGenerationWithUserTemplates(t *testing.T) {
@@ -179,10 +187,51 @@ type GetTestByNameResponse struct {
 	assert.Contains(t, code, "DeadSince *time.Time    `json:\"dead_since,omitempty\" tag1:\"value1\" tag2:\"value2\"`")
 
 	// Make sure the generated code is valid:
-	linter := new(lint.Linter)
-	problems, err := linter.Lint("test.gen.go", []byte(code))
+	checkLint(t, "test.gen.go", []byte(code))
+}
+
+func TestXGoTypeImport(t *testing.T) {
+	packageName := "api"
+	opts := Configuration{
+		PackageName: packageName,
+		Generate: GenerateOptions{
+			Models: true,
+		},
+	}
+	spec := "test_specs/x-go-type-import-pet.yaml"
+	swagger, err := util.LoadSwagger(spec)
+	require.NoError(t, err)
+
+	// Run our code generation:
+	code, err := Generate(swagger, opts)
 	assert.NoError(t, err)
-	assert.Len(t, problems, 0)
+	assert.NotEmpty(t, code)
+
+	// Check that we have valid (formattable) code:
+	_, err = format.Source([]byte(code))
+	assert.NoError(t, err)
+
+	// Check that we have a package:
+	assert.Contains(t, code, "package api")
+
+	// Check import
+	assert.Contains(t, code, `myuuid "github.com/google/uuid"`)
+
+	// Check generated struct
+	assert.Contains(t, code, "type Pet struct {\n\tAge myuuid.UUID `json:\"age\"`\n}")
+
+	// Check import
+	assert.Contains(t, code, `github.com/CavernaTechnologies/pgext`)
+
+	// Check generated struct
+	assert.Contains(t, code, "type Person struct {\n\tAge pgext.Puint `json:\"age\"`\n}")
+
+	// Check generated struct
+	assert.Contains(t, code, "type Car struct {\n\tAge int `json:\"age\"`\n}")
+
+	// Make sure the generated code is valid:
+	checkLint(t, "test.gen.go", []byte(code))
+
 }
 
 //go:embed test_spec.yaml
diff --git a/pkg/codegen/test_specs/x-go-type-import-pet.yaml b/pkg/codegen/test_specs/x-go-type-import-pet.yaml
new file mode 100644
index 0000000..9df66b5
--- /dev/null
+++ b/pkg/codegen/test_specs/x-go-type-import-pet.yaml
@@ -0,0 +1,102 @@
+openapi: "3.0.0"
+info:
+  version: 1.0.0
+  title: Swagger Petstore
+  description: A sample API that uses a petstore as an example to demonstrate features in the OpenAPI 3.0 specification
+  termsOfService: http://swagger.io/terms/
+  contact:
+    name: Swagger API Team
+    email: apiteam@swagger.io
+    url: http://swagger.io
+  license:
+    name: Apache 2.0
+    url: https://www.apache.org/licenses/LICENSE-2.0.html
+servers:
+  - url: http://petstore.swagger.io/api
+paths:
+  /pets/{id}:
+    get:
+      summary: Returns a pet by ID
+      description: Returns a pet based on a single ID
+      operationId: findPetByID
+      parameters:
+        - name: id
+          in: path
+          description: ID of pet to fetch
+          required: true
+          schema:
+            type: integer
+            format: int64
+      responses:
+        "200":
+          description: pet response
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/Pet"
+  /person/{id}:
+    get:
+      summary: Returns a person by ID
+      description: Returns a person based on a single ID
+      operationId: findPersonByID
+      parameters:
+        - name: id
+          in: path
+          description: ID of person to fetch
+          required: true
+          schema:
+            type: integer
+            format: int64
+      responses:
+        "200":
+          description: person response
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/Person"
+  /car/{id}:
+    get:
+      summary: Returns a car by ID
+      description: Returns a car based on a single ID
+      operationId: findCarByID
+      parameters:
+        - name: id
+          in: path
+          description: ID of car to fetch
+          required: true
+          schema:
+            type: integer
+            format: int64
+      responses:
+        "200":
+          description: car response
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/Car"
+
+components:
+  schemas:
+    Pet:
+      properties:
+        age:
+          x-go-type: myuuid.UUID
+          x-go-type-import:
+            path: github.com/google/uuid
+            name: myuuid
+      required:
+        - age
+    Person:
+      properties:
+        age:
+          x-go-type: pgext.Puint
+          x-go-type-import:
+            path: github.com/CavernaTechnologies/pgext
+      required:
+        - age
+    Car:
+      properties:
+        age:
+          type: integer
+      required:
+        - age
diff --git a/pkg/codegen/utils_test.go b/pkg/codegen/utils_test.go
index 0b13ee8..7bbfaff 100644
--- a/pkg/codegen/utils_test.go
+++ b/pkg/codegen/utils_test.go
@@ -14,6 +14,8 @@
 package codegen
 
 import (
+	"encoding/json"
+	"fmt"
 	"testing"
 
 	"github.com/getkin/kin-openapi/openapi3"
@@ -344,6 +346,62 @@ Line
 	}
 }
 
+func TestStringWithTypeNameToGoComment(t *testing.T) {
+	testCases := []struct {
+		input     string
+		inputName string
+		expected  string
+		message   string
+	}{
+		{
+			input:     "",
+			inputName: "",
+			expected:  "",
+			message:   "blank string should be ignored due to human unreadable",
+		},
+		{
+			input:    " ",
+			expected: "",
+			message:  "whitespace should be ignored due to human unreadable",
+		},
+		{
+			input:     "Single Line",
+			inputName: "SingleLine",
+			expected:  "// SingleLine Single Line",
+			message:   "single line comment",
+		},
+		{
+			input:     "    Single Line",
+			inputName: "SingleLine",
+			expected:  "// SingleLine     Single Line",
+			message:   "single line comment preserving whitespace",
+		},
+		{
+			input: `Multi
+Line
+  With
+    Spaces
+	And
+		Tabs
+`,
+			inputName: "MultiLine",
+			expected: `// MultiLine Multi
+// Line
+//   With
+//     Spaces
+// 	And
+// 		Tabs`,
+			message: "multi line preserving whitespaces using tabs or spaces",
+		},
+	}
+	for _, testCase := range testCases {
+		t.Run(testCase.message, func(t *testing.T) {
+			result := StringWithTypeNameToGoComment(testCase.input, testCase.inputName)
+			assert.EqualValues(t, testCase.expected, result, testCase.message)
+		})
+	}
+}
+
 func TestEscapePathElements(t *testing.T) {
 	p := "/foo/bar/baz"
 	assert.Equal(t, p, EscapePathElements(p))
@@ -376,3 +434,44 @@ func TestSchemaNameToTypeName(t *testing.T) {
 		assert.Equal(t, want, SchemaNameToTypeName(in))
 	}
 }
+
+func TestGetImports(t *testing.T) {
+	schemas := map[string]*openapi3.SchemaRef{
+		"age": {
+			Value: &openapi3.Schema{
+				ExtensionProps: openapi3.ExtensionProps{
+					Extensions: map[string]interface{}{
+						"x-go-type-import": json.RawMessage(
+							`{"name": "hello", "path": "github.com/google/uuid"}`,
+						),
+						"x-go-type": json.RawMessage(
+							"hello.UUID",
+						),
+					},
+				},
+			},
+		},
+		"name": {
+			Value: &openapi3.Schema{
+				ExtensionProps: openapi3.ExtensionProps{
+					Extensions: map[string]interface{}{"other-tag": json.RawMessage(
+						`bla`,
+					)},
+				},
+			},
+		},
+		"value": nil,
+	}
+
+	expected := map[string]goImport{
+		fmt.Sprintf("%s %q", "hello", "github.com/google/uuid"): {
+			Name: "hello",
+			Path: "github.com/google/uuid",
+		},
+	}
+
+	res, err := GetImports(schemas)
+
+	assert.NoError(t, err)
+	assert.Equal(t, expected, res)
+}
diff --git a/pkg/runtime/jsonmerge_test.go b/pkg/runtime/jsonmerge_test.go
new file mode 100644
index 0000000..8ec8dd7
--- /dev/null
+++ b/pkg/runtime/jsonmerge_test.go
@@ -0,0 +1,80 @@
+package runtime
+
+import (
+	"testing"
+
+	"github.com/stretchr/testify/assert"
+)
+
+func TestJsonMerge(t *testing.T) {
+	t.Run("when object", func(t *testing.T) {
+		t.Run("Merges properties defined in both objects", func(t *testing.T) {
+			data := `{"foo": 1}`
+			patch := `{"foo": null}`
+			expected := `{"foo":null}`
+
+			actual, err := JsonMerge([]byte(data), []byte(patch))
+			assert.NoError(t, err)
+			assert.Equal(t, expected, string(actual))
+		})
+
+		t.Run("Sets property defined in only src object", func(t *testing.T) {
+			data := `{}`
+			patch := `{"source":"merge-me"}`
+			expected := `{"source":"merge-me"}`
+
+			actual, err := JsonMerge([]byte(data), []byte(patch))
+			assert.NoError(t, err)
+			assert.Equal(t, expected, string(actual))
+		})
+
+		t.Run("Handles child objects", func(t *testing.T) {
+			data := `{"channel":{"status":"valid"}}`
+			patch := `{"channel":{"id":1}}`
+			expected := `{"channel":{"id":1,"status":"valid"}}`
+
+			actual, err := JsonMerge([]byte(data), []byte(patch))
+			assert.NoError(t, err)
+			assert.Equal(t, expected, string(actual))
+		})
+
+		t.Run("Handles empty objects", func(t *testing.T) {
+			data := `{}`
+			patch := `{}`
+			expected := `{}`
+
+			actual, err := JsonMerge([]byte(data), []byte(patch))
+			assert.NoError(t, err)
+			assert.Equal(t, expected, string(actual))
+		})
+
+		t.Run("Handles nil data", func(t *testing.T) {
+			patch := `{"foo":"bar"}`
+			expected := `{"foo":"bar"}`
+
+			actual, err := JsonMerge(nil, []byte(patch))
+			assert.NoError(t, err)
+			assert.Equal(t, expected, string(actual))
+		})
+
+		t.Run("Handles nil patch", func(t *testing.T) {
+			data := `{"foo":"bar"}`
+			expected := `{"foo":"bar"}`
+
+			actual, err := JsonMerge([]byte(data), nil)
+			assert.NoError(t, err)
+			assert.Equal(t, expected, string(actual))
+		})
+	})
+	t.Run("when array", func(t *testing.T) {
+		t.Run("it does not merge", func(t *testing.T) {
+			data := `[{"foo": 1}]`
+			patch := `[{"foo": null}]`
+			expected := `[{"foo":1}]`
+
+			actual, err := JsonMerge([]byte(data), []byte(patch))
+			assert.NoError(t, err)
+			assert.Equal(t, expected, string(actual))
+		})
+	})
+}
diff --git a/pkg/runtime/styleparam_test.go b/pkg/runtime/styleparam_test.go
index 72051a7..6271fb7 100644
--- a/pkg/runtime/styleparam_test.go
+++ b/pkg/runtime/styleparam_test.go
@@ -14,7 +14,6 @@
 package runtime
 
 import (
-	"github.com/google/uuid"
 	"testing"
 	"time"
 
@@ -679,7 +678,7 @@ func TestStyleParam(t *testing.T) {
 	assert.EqualValues(t, "date_field,1996-03-19,time_field,1996-03-19T00%3A00%3A00Z,uuid_field,baa07328-452e-40bd-aa2e-fa823ec13605", result)
 
 	// Test handling of struct that implement encoding.TextMarshaler
-  timeVal = time.Date(1996, time.March, 19, 0, 0, 0, 0, time.UTC)
+	timeVal = time.Date(1996, time.March, 19, 0, 0, 0, 0, time.UTC)
 
 	result, err = StyleParamWithLocation("simple", false, "id", ParamLocationQuery, timeVal)
 	assert.NoError(t, err)
diff --git a/pkg/types/date_test.go b/pkg/types/date_test.go
index 3d953be..2117765 100644
--- a/pkg/types/date_test.go
+++ b/pkg/types/date_test.go
@@ -52,3 +52,14 @@ func TestDate_Stringer(t *testing.T) {
 		assert.Equal(t, "2019-04-01", fmt.Sprintf("%v", d))
 	})
 }
+
+func TestDate_UnmarshalText(t *testing.T) {
+	testDate := time.Date(2022, 6, 14, 0, 0, 0, 0, time.UTC)
+	value := []byte("2022-06-14")
+
+	date := Date{}
+	err := date.UnmarshalText(value)
+
+	assert.NoError(t, err)
+	assert.Equal(t, testDate, date.Time)
+}