Skip to content

Commit

Permalink
[Go][client] make structure members pointers, provide custom marshall…
Browse files Browse the repository at this point in the history
…ing.

Fixes OpenAPITools#522
  • Loading branch information
Slavek Kabrda committed Jun 13, 2019
1 parent 19f47d0 commit 09568ce
Show file tree
Hide file tree
Showing 195 changed files with 21,441 additions and 691 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,16 @@

import org.openapitools.codegen.CliOption;
import org.openapitools.codegen.CodegenConstants;
import org.openapitools.codegen.CodegenModel;
import org.openapitools.codegen.CodegenProperty;
import org.openapitools.codegen.CodegenType;
import org.openapitools.codegen.SupportingFile;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.util.List;
import java.util.Map;

public class GoClientCodegen extends AbstractGoCodegen {

Expand Down Expand Up @@ -99,6 +103,7 @@ public void processOpts() {
supportingFiles.add(new SupportingFile("go.mod.mustache", "", "go.mod"));
supportingFiles.add(new SupportingFile("go.sum", "", "go.sum"));
supportingFiles.add(new SupportingFile(".travis.yml", "", ".travis.yml"));
supportingFiles.add(new SupportingFile("utils.mustache", "", "utils.go"));

if (additionalProperties.containsKey(WITH_GO_CODEGEN_COMMENT)) {
setWithGoCodegenComment(Boolean.parseBoolean(additionalProperties.get(WITH_GO_CODEGEN_COMMENT).toString()));
Expand All @@ -122,6 +127,32 @@ public void processOpts() {
}
}

@Override
public Map<String, Object> postProcessModels(Map<String, Object> objs) {
objs = super.postProcessModels(objs);
List<Map<String, String>> imports = (List<Map<String, String>>) objs.get("imports");

boolean addedErrorsImport = false;
List<Map<String, Object>> models = (List<Map<String, Object>>) objs.get("models");
for (Map<String, Object> m : models) {
Object v = m.get("model");
if (v instanceof CodegenModel) {
CodegenModel model = (CodegenModel) v;
if (!model.isEnum) {
imports.add(createMapping("import", "encoding/json"));
}
for (CodegenProperty param : model.vars) {
if (!addedErrorsImport && param.required) {
imports.add(createMapping("import", "errors"));
addedErrorsImport = true;
}
}
}
}

return objs;
}

/**
* Configures the type of generator.
*
Expand Down
88 changes: 87 additions & 1 deletion modules/openapi-generator/src/main/resources/go/model.mustache
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,95 @@ type {{classname}} struct {
{{#description}}
// {{{description}}}
{{/description}}
{{name}} {{#isNullable}}*{{/isNullable}}{{{dataType}}} `json:"{{baseName}}{{^required}},omitempty{{/required}}"{{#withXml}} xml:"{{baseName}}{{#isXmlAttribute}},attr{{/isXmlAttribute}}"{{/withXml}}{{#vendorExtensions.x-go-custom-tag}} {{{.}}}{{/vendorExtensions.x-go-custom-tag}}`
{{name}} *{{{dataType}}} `json:"{{baseName}},omitempty"{{#withXml}} xml:"{{baseName}}{{#isXmlAttribute}},attr{{/isXmlAttribute}}"{{/withXml}}{{#vendorExtensions.x-go-custom-tag}} {{{.}}}{{/vendorExtensions.x-go-custom-tag}}`
{{#isNullable}} isExplicitNull{{name}} bool `json:"-"{{#withXml}} xml:"-"{{/withXml}}`{{/isNullable}}
{{/vars}}
}
{{/isEnum}}

{{^isEnum}}
{{#vars}}
// Get{{name}} returns the {{name}} field if non-nil, zero value otherwise.
func (o *{{classname}}) Get{{name}}() {{dataType}} {
if o == nil || o.{{name}} == nil {
var ret {{dataType}}
return ret
}
return *o.{{name}}
}

// Get{{name}}Ok returns a tuple with the {{name}} field if it's non-nil, zero value otherwise
// and a boolean to check if the value has been set.
func (o *{{classname}}) Get{{name}}Ok() ({{dataType}}, bool) {
if o == nil || o.{{name}} == nil {
var ret {{dataType}}
return ret, false
}
return *o.{{name}}, true
}

// Has{{name}} returns a boolean if a field has been set.
func (o *{{classname}}) Has{{name}}() bool {
if o != nil && o.{{name}} != nil {
return true
}

return false
}

// Set{{name}} gets a reference to the given {{dataType}} and assigns it to the {{name}} field.
func (o *{{classname}}) Set{{name}}(v {{dataType}}) {
o.{{name}} = &v
}

{{#isNullable}}
// Set{{name}}ExplicitNull (un)sets {{name}} to be considered as explicit "null" value
// when serializing to JSON (pass true as argument to set this, false to unset)
// The {{name}} value is set to nil even if false is passed
func (o *{{classname}}) Set{{name}}ExplicitNull(b bool) {
o.{{name}} = nil
o.isExplicitNull{{name}} = b
}
{{/isNullable}}
{{/vars}}

func (o {{classname}}) MarshalJSON() ([]byte, error) {
toSerialize := map[string]interface{}{}
{{#vars}}
{{#required}}
{{! if argument is required and not nullable, it can't be nil}}
{{^isNullable}}
if o.{{name}} == nil {
return nil, errors.New("{{name}} is required and not nullable, but was not set on {{classname}}")
}{{/isNullable}}
{{! if argument is required and nullable, it *must* have isExplicitNull<name> set to true when it's nil}}
{{#isNullable}}
if o.{{name}} == nil && !o.isExplicitNull{{name}} {
return nil, errors.New("{{name}} is required and nullable, but it wasn't set to be explicit null")
}
{{/isNullable}}
{{/required}}
{{! if argument is nullable, only serialize it if it is nil *and* was explicitly set to nil}}
{{#isNullable}}
if o.{{name}} == nil {
if o.isExplicitNull{{name}} {
toSerialize["{{baseName}}"] = o.{{name}}
}
} else {
toSerialize["{{baseName}}"] = o.{{name}}
}
{{/isNullable}}
{{! if argument is not nullable, don't set it if it is nil}}
{{^isNullable}}
if o.{{name}} != nil {
toSerialize["{{baseName}}"] = o.{{name}}
}
{{/isNullable}}
{{/vars}}
return json.Marshal(toSerialize)
}
{{/isEnum}}
{{/model}}
{{/models}}
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,50 @@

Name | Type | Description | Notes
------------ | ------------- | ------------- | -------------
{{#vars}}**{{name}}** | {{#isNullable}}Pointer to {{/isNullable}}{{#isPrimitiveType}}**{{{dataType}}}**{{/isPrimitiveType}}{{^isPrimitiveType}}[**{{{dataType}}}**]({{complexType}}.md){{/isPrimitiveType}} | {{description}} | {{^required}}[optional] {{/required}}{{#readOnly}}[readonly] {{/readOnly}}{{#defaultValue}}[default to {{{.}}}]{{/defaultValue}}
{{#vars}}**{{name}}** | Pointer to {{#isPrimitiveType}}**{{{dataType}}}**{{/isPrimitiveType}}{{^isPrimitiveType}}[**{{{dataType}}}**]({{complexType}}.md){{/isPrimitiveType}} | {{description}} | {{^required}}[optional] {{/required}}{{#readOnly}}[readonly] {{/readOnly}}{{#defaultValue}}[default to {{{.}}}]{{/defaultValue}}
{{/vars}}

{{^isEnum}}
## Methods

{{#vars}}
### Get{{name}}

`func (o *{{classname}}) Get{{name}}() {{dataType}}`

Get{{name}} returns the {{name}} field if non-nil, zero value otherwise.

### Get{{name}}Ok

`func (o *{{classname}}) Get{{name}}Ok() ({{dataType}}, bool)`

Get{{name}}Ok returns a tuple with the {{name}} field if it's non-nil, zero value otherwise
and a boolean to check if the value has been set.

### Has{{name}}

`func (o *{{classname}}) Has{{name}}() bool`

Has{{name}} returns a boolean if a field has been set.

### Set{{name}}

`func (o *{{classname}}) Set{{name}}(v {{dataType}})`

Set{{name}} gets a reference to the given {{dataType}} and assigns it to the {{name}} field.

{{#isNullable}}
### Set{{name}}ExplicitNull

`func (o *{{classname}}) Set{{name}}ExplicitNull(b bool)`

Set{{name}}ExplicitNull (un)sets {{name}} to be considered as explicit "null" value
when serializing to JSON (pass true as argument to set this, false to unset)
The {{name}} value is set to nil even if false is passed
{{/isNullable}}
{{/vars}}
{{/isEnum}}

[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)

{{/model}}{{/models}}
31 changes: 31 additions & 0 deletions modules/openapi-generator/src/main/resources/go/utils.mustache
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
{{>partial_header}}
package {{packageName}}

import "time"

// Bool is a helper routine that returns a pointer to given integer value.
func Bool(v bool) *bool { return &v }

// Int is a helper routine that returns a pointer to given integer value.
func Int(v int) *int { return &v }

// Int32 is a helper routine that returns a pointer to given integer value.
func Int32(v int32) *int32 { return &v }

// Int64 is a helper routine that returns a pointer to given integer value.
func Int64(v int64) *int64 { return &v }

// Float is a helper routine that returns a pointer to given float value.
func Float(v float32) *float32 { return &v }

// Float32 is a helper routine that returns a pointer to given float value.
func Float32(v float32) *float32 { return &v }

// Float64 is a helper routine that returns a pointer to given float value.
func Float64(v float64) *float64 { return &v }

// String is a helper routine that returns a pointer to given string value.
func String(v string) *string { return &v }

// Time is helper routine that returns a pointer to given Time value.
func Time(v time.Time) *time.Time { return &v }
30 changes: 18 additions & 12 deletions samples/client/petstore/go/auth_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,9 @@ func TestOAuth2(t *testing.T) {
tokenSource := cfg.TokenSource(createContext(nil), &tok)
auth := context.WithValue(context.Background(), sw.ContextOAuth2, tokenSource)

newPet := (sw.Pet{Id: 12992, Name: "gopher",
PhotoUrls: []string{"http://1.com", "http://2.com"}, Status: "pending", Tags: []sw.Tag{sw.Tag{Id: 1, Name: "tag2"}}})
newPet := (sw.Pet{Id: sw.Int64(12992), Name: sw.String("gopher"),
PhotoUrls: &[]string{"http://1.com", "http://2.com"}, Status: sw.String("pending"),
Tags: &[]sw.Tag{sw.Tag{Id: sw.Int64(1), Name: sw.String("tag2")}}})

r, err := client.PetApi.AddPet(context.Background(), newPet)

Expand Down Expand Up @@ -73,8 +74,9 @@ func TestBasicAuth(t *testing.T) {
Password: "f4k3p455",
})

newPet := (sw.Pet{Id: 12992, Name: "gopher",
PhotoUrls: []string{"http://1.com", "http://2.com"}, Status: "pending", Tags: []sw.Tag{sw.Tag{Id: 1, Name: "tag2"}}})
newPet := (sw.Pet{Id: sw.Int64(12992), Name: sw.String("gopher"),
PhotoUrls: &[]string{"http://1.com", "http://2.com"}, Status: sw.String("pending"),
Tags: &[]sw.Tag{sw.Tag{Id: sw.Int64(1), Name: sw.String("tag2")}}})

r, err := client.PetApi.AddPet(auth, newPet)

Expand Down Expand Up @@ -104,8 +106,9 @@ func TestBasicAuth(t *testing.T) {
func TestAccessToken(t *testing.T) {
auth := context.WithValue(context.Background(), sw.ContextAccessToken, "TESTFAKEACCESSTOKENISFAKE")

newPet := (sw.Pet{Id: 12992, Name: "gopher",
PhotoUrls: []string{"http://1.com", "http://2.com"}, Status: "pending", Tags: []sw.Tag{sw.Tag{Id: 1, Name: "tag2"}}})
newPet := (sw.Pet{Id: sw.Int64(12992), Name: sw.String("gopher"),
PhotoUrls: &[]string{"http://1.com", "http://2.com"}, Status: sw.String("pending"),
Tags: &[]sw.Tag{sw.Tag{Id: sw.Int64(1), Name: sw.String("tag2")}}})

r, err := client.PetApi.AddPet(nil, newPet)

Expand Down Expand Up @@ -135,8 +138,9 @@ func TestAccessToken(t *testing.T) {
func TestAPIKeyNoPrefix(t *testing.T) {
auth := context.WithValue(context.Background(), sw.ContextAPIKey, sw.APIKey{Key: "TEST123"})

newPet := (sw.Pet{Id: 12992, Name: "gopher",
PhotoUrls: []string{"http://1.com", "http://2.com"}, Status: "pending", Tags: []sw.Tag{sw.Tag{Id: 1, Name: "tag2"}}})
newPet := (sw.Pet{Id: sw.Int64(12992), Name: sw.String("gopher"),
PhotoUrls: &[]string{"http://1.com", "http://2.com"}, Status: sw.String("pending"),
Tags: &[]sw.Tag{sw.Tag{Id: sw.Int64(1), Name: sw.String("tag2")}}})

r, err := client.PetApi.AddPet(context.Background(), newPet)

Expand Down Expand Up @@ -172,8 +176,9 @@ func TestAPIKeyNoPrefix(t *testing.T) {
func TestAPIKeyWithPrefix(t *testing.T) {
auth := context.WithValue(context.Background(), sw.ContextAPIKey, sw.APIKey{Key: "TEST123", Prefix: "Bearer"})

newPet := (sw.Pet{Id: 12992, Name: "gopher",
PhotoUrls: []string{"http://1.com", "http://2.com"}, Status: "pending", Tags: []sw.Tag{sw.Tag{Id: 1, Name: "tag2"}}})
newPet := (sw.Pet{Id: sw.Int64(12992), Name: sw.String("gopher"),
PhotoUrls: &[]string{"http://1.com", "http://2.com"}, Status: sw.String("pending"),
Tags: &[]sw.Tag{sw.Tag{Id: sw.Int64(1), Name: sw.String("tag2")}}})

r, err := client.PetApi.AddPet(nil, newPet)

Expand Down Expand Up @@ -208,8 +213,9 @@ func TestAPIKeyWithPrefix(t *testing.T) {

func TestDefaultHeader(t *testing.T) {

newPet := (sw.Pet{Id: 12992, Name: "gopher",
PhotoUrls: []string{"http://1.com", "http://2.com"}, Status: "pending", Tags: []sw.Tag{sw.Tag{Id: 1, Name: "tag2"}}})
newPet := (sw.Pet{Id: sw.Int64(12992), Name: sw.String("gopher"),
PhotoUrls: &[]string{"http://1.com", "http://2.com"}, Status: sw.String("pending"),
Tags: &[]sw.Tag{sw.Tag{Id: sw.Int64(1), Name: sw.String("tag2")}}})

r, err := client.PetApi.AddPet(context.Background(), newPet)

Expand Down
4 changes: 2 additions & 2 deletions samples/client/petstore/go/fake_api_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ func TestPutBodyWithFileSchema(t *testing.T) {
return // early return to test compilation

schema := sw.FileSchemaTestClass{
File: sw.File{SourceURI: "https://example.com/image.png"},
Files: []sw.File{{SourceURI: "https://example.com/image.png"}}}
File: &sw.File{SourceURI: sw.String("https://example.com/image.png")},
Files: &[]sw.File{{SourceURI: sw.String("https://example.com/image.png")}}}

r, err := client.FakeApi.TestBodyWithFileSchema(context.Background(), schema)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,35 @@

Name | Type | Description | Notes
------------ | ------------- | ------------- | -------------
**Name** | **string** | | [optional]
**Name** | Pointer to **string** | | [optional]

## Methods

### GetName

`func (o *AdditionalPropertiesAnyType) GetName() string`

GetName returns the Name field if non-nil, zero value otherwise.

### GetNameOk

`func (o *AdditionalPropertiesAnyType) GetNameOk() (string, bool)`

GetNameOk returns a tuple with the Name field if it's non-nil, zero value otherwise
and a boolean to check if the value has been set.

### HasName

`func (o *AdditionalPropertiesAnyType) HasName() bool`

HasName returns a boolean if a field has been set.

### SetName

`func (o *AdditionalPropertiesAnyType) SetName(v string)`

SetName gets a reference to the given string and assigns it to the Name field.


[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,35 @@

Name | Type | Description | Notes
------------ | ------------- | ------------- | -------------
**Name** | **string** | | [optional]
**Name** | Pointer to **string** | | [optional]

## Methods

### GetName

`func (o *AdditionalPropertiesArray) GetName() string`

GetName returns the Name field if non-nil, zero value otherwise.

### GetNameOk

`func (o *AdditionalPropertiesArray) GetNameOk() (string, bool)`

GetNameOk returns a tuple with the Name field if it's non-nil, zero value otherwise
and a boolean to check if the value has been set.

### HasName

`func (o *AdditionalPropertiesArray) HasName() bool`

HasName returns a boolean if a field has been set.

### SetName

`func (o *AdditionalPropertiesArray) SetName(v string)`

SetName gets a reference to the given string and assigns it to the Name field.


[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)

Expand Down
Loading

0 comments on commit 09568ce

Please sign in to comment.