Compare commits

..

101 Commits

Author SHA1 Message Date
William Cheng
2353d71d4b skip stack, dark installation due to travis issue 2018-12-01 01:04:00 +08:00
William Cheng
2f4dc9a049 Prepare 3.3.4 release (#1583)
* update release version

* update doc for 3.3.4 release

* comment out stack installation due to error in travis
2018-12-01 01:00:06 +08:00
Christophe Bornet
54b5093381 Improve online gen resolution of host for the download link (#1580)
Fix #1517
2018-11-30 22:04:17 +08:00
William Cheng
cf2ddb8b8c Fix header parameters display in the documentation (#1579)
* fix header parameters display in html

* fix cwiki header, remove test header parameter
2018-11-30 20:57:52 +08:00
William Cheng
8f8d3547f6 Update JS client dependency (#1578)
* update js dep

* fix missing comma

* remove unused test files in JS

* remove StringBooleanMap.spec.js

* remove StringBooleanMap.spec.js
2018-11-30 18:47:32 +08:00
William Cheng
eae958f293 Add "b<>com" to the list of companies using OpenAPI Generator (#1573) 2018-11-30 09:22:01 +08:00
Michael Ramstein
6930433def [elixir] Typespec - allow null on optional struct-attributes (#1514)
* Typespec - allow null on optional parameters

* Run Petstore for elixir

* considers 'nullable' in model template, fixes 'isRequired'
2018-11-29 15:58:32 +08:00
William Cheng
c537557a91 comment out haskell client build in travis 2018-11-29 11:14:00 +08:00
Akihito Nakano
f7c857cc39 [Spring] Add an option to return success code (#1197)
* Returns status code which defined at Response Object

* Tweak indent

Remove the spacer "{{#async}} ... {{/async}}" "{{^async}} ... {{/async}}"

* Update samples^

* Fix broken indentation

* Update samples

* Revert methodBody.mustache

* Revert "Fix broken indentation"
  * This reverts commit 95b6a00f8b.
* Revert "Tweak indent"
  * This reverts commit ba2cedc897.
* Revert "Returns status code which defined at Response Object"
  * This reverts commit f676a89e23.

* Example contains status code

* Update samples

./bin/spring-all-pestore.sh

* Fix syntax error

* Update samples

* Run bin/utils/ensure-up-to-date

* Make the changes an option `returnSuccessCode`

* Run bin/spring-all-pestore.sh to update samples

* Run ./bin/utils/export_docs_generators.sh
2018-11-29 11:51:25 +09:00
Simas Abramovas
777bf1f3aa Kotlin collection type (#1564)
* Allow specifying type

* Add test

* Update docs

* Don't modify types if the default option is chosen
2018-11-29 10:33:55 +08:00
William Cheng
41185d3c6f Merge branch 'master' of https://github.com/openapitools/openapi-generator 2018-11-28 22:33:54 +08:00
William Cheng
1d4e24b203 comment out c test due to timeout in travis 2018-11-28 22:17:42 +08:00
William Cheng
c63f58f1ef [Elixir] fix ":body" handling (#1504)
* Fix swagger-api/swagger-codegen/issues/8138 swagger-api/swagger-codegen#8138

When JSON payload needs to be in the body (`"in": "body"`), it must not generate a multi-part body, but embed directly in HTTP body.

* update elixir samples

* update elixir client samples

* remove double quote
2018-11-28 21:35:50 +08:00
Kiran-Sivakumar
9df70798b3 [Java][okhttp-gson] Add option to employ builders for API requests (#1341)
* Generate APIs that use the builder pattern

* Add option to use builders for API requests

* Fix template spacing

* Add new sample-generation script and generated samples

* Update docs

* Add new sample-generation script for Windows

* Replace config option with vendor extension

* Remove useBuildersForApiRequests config option

* Remove builders sample-generation scripts

* Replace config option with vendor extension in api_test template

* Remove okhttp-gson-requestBuilders sample

* Rename x-builders-for-api-requests to x-group-parameters

* Add modified api_doc.mustache under okhttp-gson resources

* Add modified README.mustache under okhttp-gson resources

* Update petstore samples

* Fix FakeApiTest.java in petstore samples

* Add whitespace to rerun checks

* Remove whitespace to rerun tests

* Fix FakeApiTest.java in parcelable petstore sample

* Update versions in samples

* Update versions in samples
2018-11-28 17:53:36 +08:00
Akihito Nakano
3efe56752e Improve error message when the spec is not found (#1495)
* Improve error message when spec not found

* Add test yaml

* Fix invalid yaml file path

* Fix typo
2018-11-28 16:50:52 +08:00
rasmusfaber
d8dde6855f Use checksum to decided if input spec has changed. (#1502) 2018-11-28 16:43:00 +08:00
meganemura
ebf67e683c Fix regexp in ruby-client (#1521)
* Fix regexp in ruby-client

* Remove tests for unknown regexp patterns
2018-11-28 16:40:58 +08:00
William Cheng
9b99b6b6bf better hanlding of string type with different format (#1558) 2018-11-28 11:21:54 +08:00
William Cheng
33016f2790 Update NPM installation instruction (#1556)
* Update NPM installation instruction

* further revise the doc
2018-11-28 00:27:35 +08:00
William Cheng
963173b357 Add link to conference presentation (#1554) 2018-11-27 23:59:23 +08:00
Michael Ramstein
d31fa4f7c4 Typespec: Fixes issue with formated primitivs (#1534) 2018-11-27 21:34:54 +08:00
Michael Ramstein
247bd68880 Decodes list with primitvs (#1536) 2018-11-27 17:00:10 +08:00
Michael Ramstein
4eae430cca [elixir] Fixes BadMapError for header parameters (#1537)
* Adds :headers as expected param mapping

* Gen Petstore
2018-11-27 16:59:16 +08:00
William Cheng
51a3a22928 Add online services to the documentation (#1550)
* update online service

* update readme with online services

* minor wording change

* revise wordings

* add links to linode logo
2018-11-27 15:51:23 +08:00
William Cheng
46a4ffe64c Skip model generation if it's a top-level map or array (#1296)
* update samples

* remove string boolean map spec

* add logic to skip array alias being generated as model

* fix alias to array

* remove unused ruby files

* remove unused ruby (oas3) files

* unalias response schema

* fix NPE when no model defined

* fix ruby openapi3 script

* update samples

* add global openapi, schemas for unaliasing

* minor code cleanup/refactoring using globalSchemas

* Revert "minor code cleanup/refactoring using globalSchemas"

This reverts commit 20a2bbc6fc.
2018-11-26 22:01:53 +08:00
Yuichi Okada
ce0253892c [PHP client] Fix README.md template for php (#1540)
* Fix README.md template for php

* update php openapi3 samples
2018-11-26 13:41:27 +08:00
William Cheng
bf2932d41c fix array of enum class in JS (#1484) 2018-11-24 17:04:59 +08:00
William Cheng
f8ada391c4 Fix boolean value handling in HTTP request body (#1515)
* fix boolean http body handling

* fix typo in parameter name
2018-11-24 16:42:32 +08:00
Christian Schneider
0ba9278308 #1506 Bump Zone.js to remove warnings when using angular >=6. (#1522)
* 1506 allow zonejs 0.7.x and 0.8.x to support a wider range of angular versions

* #1506 Removed zone.js as peer since it comes with angular itself

* #1506 Removed zone.js as peer since it comes with angular itself
2018-11-24 16:42:09 +08:00
Erik Timmers
e91d6d735d [elm] Add support for nested Lists & Dicts (#1528)
And rename Union Types to Custom Types and Aliases to Records.
2018-11-23 16:03:07 +01:00
Juan Eugenio Abadie
dd33434064 [cpp rest-sdk] Reponse headers handler (#1511)
* Add support to set a Response headers handler
* Update PetStore
* Fix missing names
* Update PetStore
2018-11-23 11:38:40 +01:00
William Cheng
cf04ba30db Fix the function name starting with numbers (#1513)
* update elixir samples

* fix function name starting with numbers

* add new files
2018-11-23 17:32:51 +08:00
William Cheng
5aa1da7c2e Add utility methods for free-form objects (isFreeFormObject) (#1338)
* add utility methods for models

* add isFreeFormObject tag

* add object mapping for elixir client

* minor fix to free form object check
2018-11-22 18:46:09 +08:00
Jon Schoning
9be5b99266 [haskell-http-client] fix typename generation bug for array params; update deps
- fix build for example-app + tests-integration in Samples (due to change in Category)

  - upgrade stack to 12.18

  - fix typename generation bug for array params
2018-11-20 18:38:07 -06:00
Alwin Garside
792f95eb09 [PHP] Use appDescription in composer.mustache (#1485)
* Use appDescription in composer.mustache

* Update petstore files

* More updated php petstore files

* Yet another updated php petstore file

* Use "{{{appDescription}}}" instead of "{{appDescription}}"
2018-11-20 10:30:14 +09:00
William Cheng
2b58f6737a fix typo in java client docstring (#1494) 2018-11-19 21:14:03 +08:00
William Cheng
363b095721 better warning, default value (#1492) 2018-11-19 20:55:29 +08:00
meganemura
b9949e1a8e Generate a ruby-client sample for OpenAPI 2.0 (#1482)
* Move output directory for bin/openapi3/ruby-client-petstore.sh

$ git mv sample/client/petstore/ruby sample/openapi3/client/petstore/ruby-client

* $ bin/ruby-client-petstore.sh

* Run bin/ruby-client-petstore.sh in bin/utils/ensure-up-to-date
2018-11-19 17:02:19 +08:00
William Cheng
f58bd6d839 fix NPE for scala gatling generator (#1479) 2018-11-19 11:06:16 +08:00
William Cheng
0e693cd9a8 Fix NPE with cpp-restsdk client generator (#1477)
* fix_cpprest_npe

* fix_code_format
2018-11-19 11:05:44 +08:00
Ludovic Montel
7f8ff35245 fix #1272 Fix wrong PHP Symfony typehint (#1453)
A model with an array property used to have the wrong PHP typehint in
the setter: the array item object type instead of "array"
2018-11-18 12:38:44 +08:00
Arshad Kazmi
2c418e1b71 Fixed scripts list url in README.md (#1481) 2018-11-18 10:20:32 +09:00
William Cheng
941b3ea015 fix NPE in the C# Nancy generator (#1478) 2018-11-17 10:11:14 -05:00
William Cheng
c656194f22 Add C template creator to project's README (#1476) 2018-11-17 18:42:40 +08:00
Steven Masala
5b57eae5de add TUI InfoTec GmbH as company (#1472) 2018-11-17 11:38:13 +08:00
William Cheng
edc05df774 Add C client generator (#516)
* add c generator (1st commit)

* udpate c model template

* more fixes

* Add string replace function for C generator (#908)

* Add string replace function for C generator

* Fixed replacement for variable only

* Fixed problem for different datatypes of paramName

* store return value of modified path

* set str_replace variable to be same as original variable.

* [C] Fixed coding style issues

* add uncrustify support

* update petstore sampmles

* add Locale.ROOT

* added test-api-client.c to include test cases for strReplace function

* added header and body mustache and made changes to ClibcurlClientCodegen.java accordingly

* [C] renamed functions in apiKey.c.mustache according to apiKey.h.mustache

* [C] changes in import statement

* renamed apiKey.h to keyValuePair.h and made necessary changes in the codes

* changed apiKey.c according to keyValuePair.h

* fixed import statement in model

* added code for generating struct in model-header.mustache

* added typedef struct for model-headers

* updated sample/client/petstore/C

* fix locale

* [C] Function addition and modification of major structs (#1020)

* added readme file

* fixed parameters in api headers functions

* made changes to add readme file and typemapping of array to list

* fixed header import statement in apiheader files

* modified struct of model type in model header

* updated sample

* modified README file

* updated sample

* parse from json function added

* modified struct and create function

* added include for model

* modified parsefromjson function

* modified struct and create function for more datatypes

* added mapping for date-time and modified model import return statement

* modified function parameters

* modified include statement

* fix function in api body

* updated sample

* clean up files

* regenerate c petstore

* fix error message when setting uncrustify

* add version to uncrustify usage

* added uncrustify rules in  mustache (#1021)

* added uncrustify rules in  mustache

* updated sample

* updated same with crustify

* updated sample with uncrusitfy 0.67

* modified readme about uncrustify requirements

* fixed mistakes in readme mustache and sample readme

* fix file import, unformat c petstore

* fix import in test files

* fix model with complexType

* fix free string, format the code using uncrustify

* modified sample

* Modified sample to check

* return type issue figured,more to do to fix it

* minor fixes to make complete code compile

* Compiling sample code. Store has issue with map.

* comment out test file generation which is not req.

* commented operation name

* fixed various issues responsible for code not compiling

* test mustache temporary for testing

* updated sample add,del,getbyid works, formparam yet to do

* few minor changes and added fuction to add different header and content type in apiClient

* added code to upload image

* added function to test upload image

* fixes for fileupload and various other small things

* fixed issue due to xml produces

* updated sample:working sample add,del,find,uploading:tocheck ,

* added free functions for variable where memory is allocated

* rename imagecontainer struct to filestruct

* fix issues with if functions for all list types

* fixed issue with primitive return type in header file

* updated sample w/ free functions

* update c samples

* remove corrupted file

* update samples

* test cases for APIs

* added function to generate test cases from new mustache

* mustache files for manual written test cases

* added default content type to application/json

* fixed issue with primitive return type

* fixed issue with bool type

* added file apiKey.c

* updated sample tested

* update c environment variable (#1090)

* add mapping for map (#1103)

* minor update

* revert list paramter check to NULL

* modified return type for primitive(map - list_t)in mustache

* removed apiClient_free as it was two times

* updated sample

* fixed issue of path parameter when string less than parameter len

* fixed issue for form paramters upload

* added checks to avoid seg faults

* updated sample

* added check for null value in form parameter

* modified size of mallocs to dynamic

* updated sample

* Add C Petstore to Travis CI (#1136)

* setup CI for C petstore

* update bash script permission

* unit petapi test

* fixed memory leak in strReplace and apiClient Functions

* modified return value for status generation

* added enum defination and functions to convert and back from string

* added function for enum and made changes to free memory at necessary places

* added datatype handling for enum

* fixes regarding memory allocation and free

* updated mustache of test files

* updated sample

* renamed manually written test files

* manual test file for pet

* cleaned common api test file for time being

* renamed test files

* added renamed test files to build test bash

* added file null pointer check

* modified uncrusitfy rules

* minor update to c templates (#1161)

* [C] Fixed enum function declaration  (#1178)

* fixed enum function declaration in model headers

* fixed enum declaration in header files for sample

* disable curl verbose mode and add response code variable

* added response code variable in apiClient struct

* modified apiClient header and source file

* added response and removed commented code api-body mustache

* removed commented code from model-body mustache

* removed unnecessary print statements from test mustache

* updated sample

* fixed spaces issue

* Better format in C templates (#1224)

* better format in the c template

* minor format fix

* [C] changed base url from static to dynamic (#1225)

* changed basePath from static to dynamic

* removed unnecessary header declaration

* updated sample

* [C] added curl version check in CMakeList.txt (#1248)

* added curl version check in CMakeList.txt

* Updated README for latest curl version

* [C] Major changes to keyValuePair function (#1282)

* removed static declaration

* changed static declaration

* added difference for string and non string

* added more code for different function for string and non string

* fix issue with param name

* change value in keyPairValue to void

* fixed issue of difference in function name cases

* added support for non char parameters in api

* fix issue of map return data

* modified manual-StoreAPI map return data handling

* fix minor mistake

* added support for map and changed code to support value of keyvaluepair as char and other

* updated sample

* fixed api header declarations

* change map declaration in header

* resolved issues realted to map data handling

* fix minor issues

* add N at start if enum variable starts with number

* override toParamName method

* changed paramters to paramName from baseName

* change variables in apibody from baseName to paramName

* Skip test file generation (#1459)

* skip test file generation

* skip overwriting CMakeLists.txt
2018-11-17 01:32:18 +08:00
William Cheng
6ab6896a13 comment out dart2 test, update rust server samples (#1471) 2018-11-17 01:27:07 +08:00
Benjamin Gill
32b8d7fee7 [rust-server] Always derive Debug (#1404)
* Add test for file response

* Always derive Debug

Now that we're using a byte array, we can guarantee that deriving Debug will always work
2018-11-16 12:28:05 +00:00
Shengpeng Liu
dc3a3dd15a Fix openapi_types generation error (#1256) 2018-11-15 21:38:45 +08:00
William Cheng
8d9542207a Prepare 3.3.4 snapshot (#1450)
* change version to 3.3.4-snapshot

* updat readme

* update samples
2018-11-15 16:21:15 +08:00
William Cheng
31d9928734 Revert "force deployment"
This reverts commit e5c0d227ab.
2018-11-15 12:25:14 +08:00
William Cheng
e5c0d227ab force deployment 2018-11-15 11:39:14 +08:00
James Addyman
653601bef2 Fix #1424 [SWIFT4] Date Encoding Issues (#1442)
Ensure the same date format string is used throughout the generated code (use the one set in Configuration.swift).

Ensure the same date formatter options are used when encoding dates as well as decoding dates. If a consumer has set their own date formatter on CodableHelper, use that when encoding dates too.

Adds DateFormatTests to the SWIFT4 unit tests.

Updates the SWIFT4 petstore samples
2018-11-15 11:20:39 +09:00
William Cheng
7564d629e7 prepare 3.3.3 release (#1447) 2018-11-14 23:56:58 +08:00
William Cheng
f647b2f24b Add file post-processing to C++ client, server generators (#1440)
* add file post processing to cpp generators

* use clang to auto format cpp-restsdk code

* restore cpp-restsdk samples without clang format
2018-11-14 16:43:14 +08:00
William Cheng
0165b0fb33 test all generators with fake petstore spec 2.0, 3.0 (#1439) 2018-11-14 15:55:09 +08:00
Jim Schubert
df1819daa9 C# template refactor (#737)
* [csharp] Refactor to support third-party customization more easily

* [csharp] Regenerate OpenAPIClient sample

* create new csharp-refactor client gen

* update samples

* fix Locale.ROOT

* fix import

* remove outdated files, update samples
2018-11-14 14:41:42 +08:00
William Cheng
3c28946f1e [Android] Fix compilation errors when there's no model defined (#1438)
* remove model import when there is no model

* fix android http client no model issu due to import
2018-11-14 14:02:05 +08:00
TNM Technologies
22902e72a1 fix(#1423): [JAVA] generating Map with jaxrs-reasteasy does not import (#1426)
* fix(#1423): [JAVA] generating Map with jaxrs-reasteasy does not import
the hashmap

https://github.com/OpenAPITools/openapi-generator/issues/1423

* fix(#1423): fix ensure-up-to-date issues for jaxrs-resteasy joda
samples

https://github.com/OpenAPITools/openapi-generator/issues/1423
2018-11-14 10:18:53 +08:00
William Cheng
efde4a8eb8 Fix issue with C# generator when the model name is "File" (#1428)
* fix get schema type in abstract c# class

* update c# petstore sample
2018-11-14 09:43:31 +08:00
Akihito Nakano
c8837ea414 Change entrypoint to docker-entrypoint.sh (#1413)
Run entrypoint script
2018-11-13 17:24:04 +09:00
William Cheng
7c3a2a5c07 Fix run-in-docker by disabling useSystemClassLoader (#1418)
* test run-in-docker in travis

* fix command path

* correct batch mode arg

* disable useSystemClassLoader
2018-11-12 22:07:46 +08:00
William Cheng
7e3149e675 fix npe when paramName is null (#1416) 2018-11-12 22:06:58 +08:00
meganemura
9db62f459a Fix return_type parameter examples in ruby-client (#1399)
* Fix return_type parameter examples

* $ bin/openapi3/ruby-client-petstore.sh
2018-11-12 14:26:05 +08:00
William Cheng
c7349c7f88 Add top level x-group-parameters support (#1405)
* add top level x-group-parameters support

* update petstore samples
2018-11-12 14:25:32 +08:00
William Cheng
69a766882d Add tip about running online openapi-generator via Docker (#1415)
Add tip about running online openapi-generator via Docker
2018-11-12 11:37:30 +08:00
William Cheng
7ce38aae38 Remove duplicated imports (#1414)
* remove duplicated imports

* fix model import in java

* update generator docs

* fix model import for retrofit2 client
2018-11-11 21:33:28 +08:00
sunn
fd46b4e566 Sanitize Model Import (#1411) 2018-11-10 21:07:49 +01:00
James Addyman
5711985ac3 Fix swift4 1406 (#1407)
* Fix warnings produced when using Swift 4.2

* Update Petstore client for Swift 4
2018-11-10 13:59:58 +09:00
William Cheng
7c6beb9692 update generator doc 2018-11-10 00:28:08 +08:00
Simas Abramovas
f802e63f9f Add parcelizeModels cli option (#1289)
* Add parcelizeModels cli option

* Add info log to clarify the parcelization requirements.

* Update docs
2018-11-09 23:51:27 +08:00
sunn
0ed02c8e91 Fixes double prefixing during model import (#1398) 2018-11-09 16:49:47 +01:00
Eivind Bergstøl
93e2fc6355 Fixes an issue where code generator for Java produces not compileable (#1357)
code if the yml-definition does not have any type definitions. This
is normal if the api only uses simple datatypes (Int, String) for
inout/output.
2018-11-09 23:48:26 +08:00
William Cheng
60bc19e830 Add file post-processing to PHP generators (#1402)
* add file post processing to php

* restore php petstore client
2018-11-09 23:45:21 +08:00
Benjamin Gill
4742f0086b [rust-server] Re-instate ApiRequestParser (#1388)
* Re-instate ApiRequestParser

It turns out I was over-eager when removing file support and accidentally deleted some code that should have been kept. See https://github.com/OpenAPITools/openapi-generator/pull/547/files#diff-684007b298ee5998fa30732c261ea2fcL469.

* Don't do html escaping of parameters
2018-11-09 11:23:59 +00:00
William Cheng
1522855915 update python petstore samples 2018-11-08 21:47:16 +08:00
William Cheng
3969afb2ff Add file post-processing to Kotlin generators (#1400)
* add post processing to kotlin file

* restore kotlin samples
2018-11-08 17:40:39 +08:00
William Cheng
2ef499faf3 [python] Avoid creating unused ThreadPools (#1387)
* Avoid creating unused ThreadPools

Instead, create ApiClient.pool on first request for .pool property.

avoids spawning n-cpus threads (the default for ThreadPool) at instantiation of every ApiClient

* update doc

* set pool_thread to None
2018-11-08 17:39:20 +08:00
William Cheng
34945427d4 fix java exception in apex codegen (#1395) 2018-11-07 22:32:22 +08:00
Benjamin Gill
5849dbaaca Add tests for inline objects (#1331)
I think these tests cover all the problems with rust-server and inline objects I know about. This should show us when we've fixed the problem.

Also fixes a CI failure.
2018-11-07 11:07:53 +00:00
Steven Masala
73162cbcca fix name sanitation when using kebab case filenaming (#1314)
* fix name sanitation when using kebab case filenaming

* remove whitespaces
2018-11-07 15:52:51 +08:00
Guy Gershoni
0e2e1bf715 Added tests and fix for issue #1392. Fix regex generated in Ruby client. (#1393)
* Added tests and fix for issue #1392. Param validation with regex not recognizing \d correctly in Ruby client.

* Added generated files to pass ./bin/utils/ensure-up-to-date which is run by circleci
2018-11-07 12:08:23 +08:00
William Cheng
f21640f6a1 update spring samples 2018-11-07 11:46:17 +08:00
Konstantin Pavlov
301208a785 JavaSpring: pojo: fix javadoc comment (#1384) 2018-11-07 11:26:56 +08:00
William Cheng
4245cf42dd update generator doc 2018-11-07 01:02:44 +08:00
Christophe Bornet
2184a8a9b4 [Flask] Upgrade to flask-connexion 2.0.0 (#1382)
Fix #323
2018-11-06 18:37:50 +08:00
Benjamin Gill
30bfebfa16 Rust server html (#1329)
Builds on #1180 by @colelawrence. This addition to the rust-server generator enables the use of text/html responses as plaintext.

I've added an html endpoint to the sample to demonstrate that this works (and fixed the problem that that uncovered).
2018-11-05 16:14:23 +00:00
Martin Fidczuk
303b469fae Allow package version to be passed on CLI (Rust fix) (#1286)
This MR allows package version to be specified in Rust in the generate argument list, with the argument `-DpackageVersion=<package_version>`. If this argument is present then the version in the resulting Cargo.toml file will be the passed value. If this argument is not present then the version in the OpenAPI definition file will be used, as per current behavior.
2018-11-05 16:12:43 +00:00
William Cheng
c95b1f4545 fix incorrect patternin aspnetcore (#1371) 2018-11-05 10:21:55 +08:00
William Cheng
fbc3ff8766 Add a link to an article about openapi-generator (#1370) 2018-11-05 08:17:22 +08:00
Nathan Broadbent
63b1c233c9 Fix issue with Ruby client where strings from example properties are not wrapped with quotes (#987) 2018-11-04 17:10:35 +08:00
andreas-eternach
eb5a8cc752 feat: OpenApi-generation from within eclipse (#509) (#1332)
* feat: OpenApi-generation from within eclipse (#509)

* Added life-cycle-mapping for recognition by M2E
* Make BuildContext injectable by M2E in oder to detect if json-source
has been modified and a regeneration is required.

* core: fix indentation problems, remove commented code
2018-11-04 17:07:33 +08:00
Benoît Courtine
293d29ab3b Fixes bug #1339. Array and Map inner schema can be missing. In this case, it must default to String. (#1363) 2018-11-03 22:19:19 +08:00
Kiran-Sivakumar
078b04deac [Java][okhttp-gson] Add new ApiClient constructors for access token retry (#1319)
* Add new ApiClient constructors for access token retry

* Update samples

* Update security samples
2018-11-03 22:10:16 +08:00
Kay Schecker
7eb9cda1e0 Added hint for npm package wrapper to README (#1350)
* Added hint for npm package wrapper to README

* Added manual how to use and install NPM package globally
2018-11-03 22:06:11 +08:00
Vasili Puchko
ac6fd3f79f Update gradle plugin's Readme.md (#1356)
Add a note about use of `systemProperties` since some options are confusing and hard to guess how to use correctly. The only source I was able to find how to configure it in the way I need was a comment to issue https://github.com/OpenAPITools/openapi-generator/issues/551#issuecomment-411686091
2018-11-03 21:58:43 +08:00
sunn
f8f3a08282 [cpp-pistache]Add support for map (#1359)
* Add support for map
* Add support for nested maps
* Simplify Array and Map Helper
* Use const reference wherever possible
2018-11-03 14:09:31 +01:00
William Cheng
36991a4e14 Improve ensure-up-to-date script (#1362)
* improve ensure-up-to-date script

* trigger build failure

* use exit 1 instead

* fix build failure

* update samples
2018-11-02 15:38:34 +08:00
Juan Eugenio Abadie
ecff8b5d00 [cpp rest-sdk]Fix precision (#1293)
* Convert floating point numbers to string with higher precision
* Update PetStore
2018-11-01 20:25:38 +01:00
Ysawa
521f5fafa3 Fix defaultValue for String schama in Dart (#1342) 2018-11-01 17:50:01 +08:00
William Cheng
02e85cc417 Prepare v3.3.3-SNAPSHOT (#1355)
* prepare 3.3.3-snapshot

* update petstore samples
2018-11-01 10:42:26 +08:00
2002 changed files with 66585 additions and 12685 deletions

View File

@@ -51,9 +51,9 @@ addons:
before_install:
# install haskell
- curl -sSL https://get.haskellstack.org/ | sh
- stack upgrade
- stack --version
#- curl -sSL https://get.haskellstack.org/ | sh
#- stack upgrade
#- stack --version
# install rust
- curl https://sh.rustup.rs -sSf | sh -s -- -y -v
# required when sudo: required for the Ruby petstore tests
@@ -75,11 +75,11 @@ before_install:
- sudo apt-get install -qq curl
# install dart
#- sudo apt-get update
- sudo apt-get install apt-transport-https
- sudo sh -c 'curl https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add -'
- sudo sh -c 'curl https://storage.googleapis.com/download.dartlang.org/linux/debian/dart_stable.list > /etc/apt/sources.list.d/dart_stable.list'
- sudo apt-get update
- sudo apt-get install dart
#- sudo apt-get install apt-transport-https
#- sudo sh -c 'curl https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add -'
#- sudo sh -c 'curl https://storage.googleapis.com/download.dartlang.org/linux/debian/dart_stable.list > /etc/apt/sources.list.d/dart_stable.list'
#- sudo apt-get update
#- sudo apt-get install dart
# install perl module
#- cpanm --local-lib=~/perl5 local::lib && eval $(perl -I ~/perl5/lib/perl5/ -Mlocal::lib)
#- cpanm Test::Exception Test::More Log::Any LWP::UserAgent JSON URI:Query Module::Runtime DateTime Module::Find Moose::Role
@@ -109,8 +109,8 @@ install:
- gcc -v
- echo $CC
- echo $CXX
- pub version
- dart --version
#- pub version
#- dart --version
script:
# fail fast
@@ -122,8 +122,8 @@ script:
# fail if generators contain tab '\t'
- /bin/bash ./bin/utils/detect_tab_in_java_class.sh
# run integration tests defined in maven pom.xml
- mvn --quiet clean install
- mvn --quiet verify -Psamples
- ./run-in-docker.sh mvn --quiet --batch-mode clean install
- mvn --quiet --batch-mode verify -Psamples
after_success:
# push to maven repo
- if [ $SONATYPE_USERNAME ] && [ -z $TRAVIS_TAG ] && [ "$TRAVIS_PULL_REQUEST" == "false" ]; then
@@ -148,7 +148,7 @@ after_success:
## docker: build and push openapi-generator-online to DockerHub
- if [ $DOCKER_HUB_USERNAME ]; then echo "$DOCKER_HUB_PASSWORD" | docker login --username=$DOCKER_HUB_USERNAME --password-stdin && docker build -t $DOCKER_GENERATOR_IMAGE_NAME ./modules/openapi-generator-online && if [ ! -z "$TRAVIS_TAG" ]; then docker tag $DOCKER_GENERATOR_IMAGE_NAME:latest $DOCKER_GENERATOR_IMAGE_NAME:$TRAVIS_TAG; fi && if [ ! -z "$TRAVIS_TAG" ] || [ "$TRAVIS_BRANCH" = "master" ]; then docker push $DOCKER_GENERATOR_IMAGE_NAME && echo "Pushed to $DOCKER_GENERATOR_IMAGE_NAME"; fi; fi
## docker: build cli image and push to Docker Hub
- if [ $DOCKER_HUB_USERNAME ]; then echo "$DOCKER_HUB_PASSWORD" | docker login --username=$DOCKER_HUB_USERNAME --password-stdin && docker build -t $DOCKER_CODEGEN_CLI_IMAGE_NAME ./modules/openapi-generator-cli && if [ ! -z "$TRAVIS_TAG" ]; then docker tag $DOCKER_CODEGEN_CLI_IMAGE_NAME:latest $DOCKER_CODEGEN_CLI_IMAGE_NAME:$TRAVIS_TAG; fi && if [ ! -z "$TRAVIS_TAG" ] || [ "$TRAVIS_BRANCH" = "master" ]; then docker push $DOCKER_CODEGEN_CLI_IMAGE_NAME && echo "Pushed to $DOCKER_CODEGEN_CLI_IMAGE_NAME"; fi; fi
- if [ $DOCKER_HUB_USERNAME ]; then echo "$DOCKER_HUB_PASSWORD" | docker login --username=$DOCKER_HUB_USERNAME --password-stdin && cp docker-entrypoint.sh ./modules/openapi-generator-cli && docker build -t $DOCKER_CODEGEN_CLI_IMAGE_NAME ./modules/openapi-generator-cli && if [ ! -z "$TRAVIS_TAG" ]; then docker tag $DOCKER_CODEGEN_CLI_IMAGE_NAME:latest $DOCKER_CODEGEN_CLI_IMAGE_NAME:$TRAVIS_TAG; fi && if [ ! -z "$TRAVIS_TAG" ] || [ "$TRAVIS_BRANCH" = "master" ]; then docker push $DOCKER_CODEGEN_CLI_IMAGE_NAME && echo "Pushed to $DOCKER_CODEGEN_CLI_IMAGE_NAME"; fi; fi
env:
- DOCKER_GENERATOR_IMAGE_NAME=openapitools/openapi-generator-online DOCKER_CODEGEN_CLI_IMAGE_NAME=openapitools/openapi-generator-cli NODE_ENV=test CC=gcc-5 CXX=g++-5

View File

@@ -2,16 +2,11 @@
<div align="center">
[Master](https://github.com/OpenAPITools/openapi-generator/tree/master) (`3.3.2`): [![Build Status](https://img.shields.io/travis/OpenAPITools/openapi-generator/master.svg?label=Integration%20Test)](https://travis-ci.org/OpenAPITools/openapi-generator)
[Master](https://github.com/OpenAPITools/openapi-generator/tree/master) (`3.3.4`): [![Build Status](https://img.shields.io/travis/OpenAPITools/openapi-generator/master.svg?label=Integration%20Test)](https://travis-ci.org/OpenAPITools/openapi-generator)
[![Integration Test2](https://circleci.com/gh/OpenAPITools/openapi-generator.svg?style=shield)](https://circleci.com/gh/OpenAPITools/openapi-generator)
[![Run Status](https://api.shippable.com/projects/5af6bf74e790f4070084a115/badge?branch=master)](https://app.shippable.com/github/OpenAPITools/openapi-generator)
[![Windows Test](https://ci.appveyor.com/api/projects/status/github/openapitools/openapi-generator?branch=master&svg=true&passingText=Windows%20Test%20-%20OK&failingText=Windows%20Test%20-%20Fails)](https://ci.appveyor.com/project/WilliamCheng/openapi-generator-wh2wu)
[`3.4.x`](https://github.com/OpenAPITools/openapi-generator/tree/3.4.x) branch: [![Build Status](https://img.shields.io/travis/OpenAPITools/openapi-generator/3.4.x.svg?label=Integration%20Test)](https://travis-ci.org/OpenAPITools/openapi-generator)
[![Integration Test2](https://circleci.com/gh/OpenAPITools/openapi-generator/tree/3.4.x.svg?style=shield)](https://circleci.com/gh/OpenAPITools/openapi-generator)
[![Run Status](https://api.shippable.com/projects/5af6bf74e790f4070084a115/badge?branch=3.4.x)](https://app.shippable.com/github/OpenAPITools/openapi-generator)
[![Windows Test](https://ci.appveyor.com/api/projects/status/github/openapitools/openapi-generator?branch=3.4.x&svg=true&passingText=Windows%20Test%20-%20OK&failingText=Windows%20Test%20-%20Fails)](https://ci.appveyor.com/project/WilliamCheng/openapi-generator-wh2wu)
[`4.0.x`](https://github.com/OpenAPITools/openapi-generator/tree/4.0.x) branch: [![Build Status](https://img.shields.io/travis/OpenAPITools/openapi-generator/4.0.x.svg?label=Integration%20Test)](https://travis-ci.org/OpenAPITools/openapi-generator)
[![Integration Test2](https://circleci.com/gh/OpenAPITools/openapi-generator/tree/4.0.x.svg?style=shield)](https://circleci.com/gh/OpenAPITools/openapi-generator)
[![Run Status](https://api.shippable.com/projects/5af6bf74e790f4070084a115/badge?branch=4.0.x)](https://app.shippable.com/github/OpenAPITools/openapi-generator)
@@ -47,7 +42,7 @@ OpenAPI Generator allows generation of API client libraries (SDK generation), se
| | Languages/Frameworks |
|-|-|
**API clients** | **ActionScript**, **Ada**, **Apex**, **Bash**, **C#** (.net 2.0, 3.5 or later), **C++** (cpprest, Qt5, Tizen), **Clojure**, **Dart (1.x, 2.x)**, **Elixir**, **Elm**, **Eiffel**, **Erlang**, **Go**, **Groovy**, **Haskell** (http-client, Servant), **Java** (Jersey1.x, Jersey2.x, OkHttp, Retrofit1.x, Retrofit2.x, Feign, RestTemplate, RESTEasy, Vertx, Google API Client Library for Java, Rest-assured, Spring 5 Web Client), **Kotlin**, **Lua**, **Node.js** (ES5, ES6, AngularJS with Google Closure Compiler annotations, Flow types) **Objective-C**, **Perl**, **PHP**, **PowerShell**, **Python**, **R**, **Ruby**, **Rust** (rust, rust-server), **Scala** (akka, http4s, scalaz, swagger-async-httpclient), **Swift** (2.x, 3.x, 4.x), **Typescript** (AngularJS, Angular (2.x - 7.x), Aurelia, Axios, Fetch, Inversify, jQuery, Node)
**API clients** | **ActionScript**, **Ada**, **Apex**, **Bash**, **C**, **C#** (.net 2.0, 3.5 or later), **C++** (cpprest, Qt5, Tizen), **Clojure**, **Dart (1.x, 2.x)**, **Elixir**, **Elm**, **Eiffel**, **Erlang**, **Go**, **Groovy**, **Haskell** (http-client, Servant), **Java** (Jersey1.x, Jersey2.x, OkHttp, Retrofit1.x, Retrofit2.x, Feign, RestTemplate, RESTEasy, Vertx, Google API Client Library for Java, Rest-assured, Spring 5 Web Client), **Kotlin**, **Lua**, **Node.js** (ES5, ES6, AngularJS with Google Closure Compiler annotations, Flow types) **Objective-C**, **Perl**, **PHP**, **PowerShell**, **Python**, **R**, **Ruby**, **Rust** (rust, rust-server), **Scala** (akka, http4s, scalaz, swagger-async-httpclient), **Swift** (2.x, 3.x, 4.x), **Typescript** (AngularJS, Angular (2.x - 7.x), Aurelia, Axios, Fetch, Inversify, jQuery, Node)
**Server stubs** | **Ada**, **C#** (ASP.NET Core, NancyFx), **C++** (Pistache, Restbed), **Erlang**, **Go** (net/http, Gin), **Haskell** (Servant), **Java** (MSF4J, Spring, Undertow, JAX-RS: CDI, CXF, Inflector, RestEasy, Play Framework, [PKMST](https://github.com/ProKarma-Inc/pkmst-getting-started-examples)), **Kotlin** (Spring Boot), **PHP** (Laravel, Lumen, Slim, Silex, [Symfony](https://symfony.com/), [Zend Expressive](https://github.com/zendframework/zend-expressive)), **Python** (Flask), **NodeJS**, **Ruby** (Sinatra, Rails5), **Rust** (rust-server), **Scala** ([Finch](https://github.com/finagle/finch), [Lagom](https://github.com/lagom/lagom), Scalatra)
**API documentation generators** | **HTML**, **Confluence Wiki**
**Configuration files** | [**Apache2**](https://httpd.apache.org/)
@@ -65,6 +60,7 @@ OpenAPI Generator allows generation of API client libraries (SDK generation), se
- [1.4 - Build Projects](#14---build-projects)
- [1.5 - Homebrew](#15---homebrew)
- [1.6 - Docker](#16---docker)
- [1.7 - NPM](#17---npm)
- [2 - Getting Started](#2---getting-started)
- [3 - Usage](#3---usage)
- [3.1 - Customization](#31---customization)
@@ -87,10 +83,8 @@ The OpenAPI Specification has undergone 3 revisions since initial creation in 20
OpenAPI Generator Version | Release Date | Notes
---------------------------- | ------------ | -----
4.0.0 (upcoming major release) [SNAPSHOT](https://oss.sonatype.org/content/repositories/snapshots/org/openapitools/openapi-generator-cli/4.0.0-SNAPSHOT/)| TBD | Major release with breaking changes (no fallback)
3.4.0 (upcoming minor release) [SNAPSHOT](https://oss.sonatype.org/content/repositories/snapshots/org/openapitools/openapi-generator-cli/3.4.0-SNAPSHOT/)| 01.11.2018 | Minor release (breaking changes with fallbacks)
3.3.2 (current master, upcoming patch release) [SNAPSHOT](https://oss.sonatype.org/content/repositories/snapshots/org/openapitools/openapi-generator-cli/3.3.2-SNAPSHOT/) | 31.10.2018 | Bugfix release
[3.3.2](https://github.com/OpenAPITools/openapi-generator/releases/tag/v3.3.2) (latest stable release) | 31.10.2018 | Bugfix release
4.0.0 (upcoming major release) [SNAPSHOT](https://oss.sonatype.org/content/repositories/snapshots/org/openapitools/openapi-generator-cli/4.0.0-SNAPSHOT/)| 20.12.2018 | Major release with breaking changes (with or without fallback)
[3.3.4](https://github.com/OpenAPITools/openapi-generator/releases/tag/v3.3.4) (latest stable release) | 30.11.2018 | Bugfix release
OpenAPI Spec compatibility: 1.0, 1.1, 1.2, 2.0, 3.0
@@ -146,16 +140,16 @@ See the different versions of the [openapi-generator-cli](https://mvnrepository.
If you're looking for the latest stable version, you can grab it directly from Maven.org (Java 8 runtime at a minimum):
JAR location: `http://central.maven.org/maven2/org/openapitools/openapi-generator-cli/3.3.2/openapi-generator-cli-3.3.2.jar`
JAR location: `http://central.maven.org/maven2/org/openapitools/openapi-generator-cli/3.3.4/openapi-generator-cli-3.3.4.jar`
For **Mac/Linux** users:
```sh
wget http://central.maven.org/maven2/org/openapitools/openapi-generator-cli/3.3.2/openapi-generator-cli-3.3.2.jar -O openapi-generator-cli.jar
wget http://central.maven.org/maven2/org/openapitools/openapi-generator-cli/3.3.4/openapi-generator-cli-3.3.4.jar -O openapi-generator-cli.jar
```
For **Windows** users, you will need to install [wget](http://gnuwin32.sourceforge.net/packages/wget.htm) or you can use Invoke-WebRequest in PowerShell (3.0+), e.g.
```
Invoke-WebRequest -OutFile openapi-generator-cli.jar http://central.maven.org/maven2/org/openapitools/openapi-generator-cli/3.3.2/openapi-generator-cli-3.3.2.jar
Invoke-WebRequest -OutFile openapi-generator-cli.jar http://central.maven.org/maven2/org/openapitools/openapi-generator-cli/3.3.4/openapi-generator-cli-3.3.4.jar
```
After downloading the JAR, run `java -jar openapi-generator-cli.jar help` to show the usage.
@@ -215,7 +209,7 @@ To build from source, you need the following installed and available in your `$P
* [Java 8](http://java.oracle.com)
* [Apache maven 3.3.3 or greater](http://maven.apache.org/)
* [Apache maven 3.3.4 or greater](http://maven.apache.org/)
After cloning the project, you can build it from source with this command:
```sh
@@ -284,13 +278,13 @@ GEN_IP=$(docker inspect --format '{{.NetworkSettings.IPAddress}}' $CID)
-d '{"openAPIUrl": "https://raw.githubusercontent.com/openapitools/openapi-generator/master/modules/openapi-generator/src/test/resources/2_0/petstore.yaml"}' \
'http://localhost:8888/api/gen/clients/ruby'
{"code":"c2d483d3-3672-40e9-91df-b9ffd18d22b8","link":"http://localhost:8888/api/gen/download/c2d483d3-3672-40e9-91df-b9ffd18d22b8"}
{"code":"c2d483.3.4672-40e9-91df-b9ffd18d22b8","link":"http://localhost:8888/api/gen/download/c2d483.3.4672-40e9-91df-b9ffd18d22b8"}
# Download the generated zip file
> wget http://localhost:8888/api/gen/download/c2d483d3-3672-40e9-91df-b9ffd18d22b8
> wget http://localhost:8888/api/gen/download/c2d483.3.4672-40e9-91df-b9ffd18d22b8
# Unzip the file
> unzip c2d483d3-3672-40e9-91df-b9ffd18d22b8
> unzip c2d483.3.4672-40e9-91df-b9ffd18d22b8
# Shutdown the openapi generator image
> docker stop $CID && docker rm $CID
@@ -346,6 +340,30 @@ cd /vagrant
./run-in-docker.sh mvn package
```
### [1.7 - NPM](#table-of-contents)
There is also an [NPM package wrapper](https://www.npmjs.com/package/@openapitools/openapi-generator-cli) available for different platforms (e.g. Linux, Mac, Windows). (JVM is still required)
Please see the [project's README](https://github.com/openapitools/openapi-generator-cli) there for more information.
Install it globally to get the CLI available on the command line:
```sh
npm install @openapitools/openapi-generator-cli -g
openapi-generator version
```
Or install a particualar OpenAPI Generator version (e.g. v3.3.4):
```sh
npm install @openapitools/openapi-generator-cli@cli-3.3.4 -g
```
Or install it as dev-dependency:
```sh
npm install @openapitools/openapi-generator-cli -D
```
## [2 - Getting Started](#table-of-contents)
To generate a PHP client for [petstore.yaml](https://raw.githubusercontent.com/openapitools/openapi-generator/master/modules/openapi-generator/src/test/resources/2_0/petstore.yaml), please run the following
@@ -451,7 +469,7 @@ Other languages have petstore samples, too:
./bin/objc-petstore.sh
```
... and others. [Here is a list of all scripts.](wiki/Samples-folder#scripts)
... and others. [Here is a list of all scripts.](https://github.com/OpenAPITools/openapi-generator/wiki/Samples-folder#scripts)
### [3.1 - Customization](#table-of-contents)
@@ -463,6 +481,15 @@ Please refer to [integration.md](docs/integration.md) on how to integrate OpenAP
### [3.3 - Online OpenAPI generator](#table-of-contents)
Here are the public online services:
- latest stable version: http://api.openapi-generator.tech
- latest master: http://api-latest-master.openapi-generator.tech (updated with latest master every hour)
The server is sponsored by [Linode](https://www.linode.com/) [![Linode Logo](https://www.linode.com/media/images/logos/standard/light/linode-logo_standard_light_small.png)](https://www.linode.com/)
(These services are beta and do not have any guarantee on service level)
Please refer to [online-openapi-generator.md](docs/online-openapi-generator.md) on how to run and use the `openapi-generator-online` - a web service for `openapi-generator`.
### [3.4 - License information on Generated Code](#table-of-contents)
@@ -478,6 +505,7 @@ When code is generated from this project, it shall be considered **AS IS** and o
Here are some companies/projects (alphabetical order) using OpenAPI Generator in production. To add your company/project to the list, please visit [README.md](README.md) and click on the icon to edit the page.
- [Angular.Schule](https://angular.schule/)
- [b<>com](https://b-com.com/en)
- [Bithost GmbH](https://www.bithost.ch)
- [Boxever](https://www.boxever.com/)
- [GMO Pepabo](https://pepabo.com/en/)
@@ -489,6 +517,7 @@ Here are some companies/projects (alphabetical order) using OpenAPI Generator in
- [REST United](https://restunited.com)
- [Suva](https://www.suva.ch/)
- [Telstra](https://dev.telstra.com)
- [TUI InfoTec GmbH](http://www.tui-infotec.com/)
- [unblu inc.](https://www.unblu.com/)
- [Zalando](https://www.zalando.com)
@@ -503,7 +532,8 @@ Here are some companies/projects (alphabetical order) using OpenAPI Generator in
- 2018/07/19 - [OpenAPI Generator Contribution Quickstart - RingCentral Go SDK](https://medium.com/ringcentral-developers/openapi-generator-for-go-contribution-quickstart-8cc72bf37b53) by [John Wang](https://github.com/grokify)
- 2018/08/22 - [OpenAPI Generatorのプロジェクト構成などのメモ](https://yinm.info/20180822/) by [Yusuke Iinuma](https://github.com/yinm)
- 2018/10/31 - [A node package wrapper for openapi-generator](https://github.com/HarmoWatch/openapi-generator-cli)
- 2018/11/03 - [OpenAPI Generator + golang + Flutter でアプリ開発](http://ryuichi111std.hatenablog.com/entry/2018/11/03/214005) by [Ryuichi Daigo](https://github.com/ryuichi111)
- 2018/11/19 - [OpenAPIs are everywhere](https://youtu.be/-lDot4Yn7Dg) by [Jeremie Bresson (Unblu)](https://github.com/jmini) at [EclipseCon Europe 2018](https://www.eclipsecon.org/europe2018)
## [6 - About Us](#table-of-contents)
@@ -527,6 +557,7 @@ Here is a list of template creators:
* Akka-Scala: @cchafer
* Apex: @asnelling
* Bash: @bkryza
* C: @PowerOfCreation @zhemant
* C++ REST: @Danielku15
* C# (.NET 2.0): @who
* C# (.NET Standard 1.3 ): @Gronsak
@@ -655,6 +686,7 @@ If you want to join the committee, please kindly apply by sending an email to te
| Android | @jaz-ah (2017/09) |
| Apex | |
| Bash | @frol (2017/07) @bkryza (2017/08) @kenjones-cisco (2017/09) |
| C | @zhemant (2018/11) |
| C++ | @ravinikam (2017/07) @stkrwork (2017/07) @fvarose (2017/11) @etherealjoy (2018/02) @martindelille (2018/03) |
| C# | @mandrean (2017/08) @jimschubert (2017/09) |
| Clojure | |

32
bin/c-petstore.sh Executable file
View File

@@ -0,0 +1,32 @@
#!/bin/sh
SCRIPT="$0"
echo "# START SCRIPT: $SCRIPT"
while [ -h "$SCRIPT" ] ; do
ls=`ls -ld "$SCRIPT"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
SCRIPT="$link"
else
SCRIPT=`dirname "$SCRIPT"`/"$link"
fi
done
if [ ! -d "${APP_DIR}" ]; then
APP_DIR=`dirname "$SCRIPT"`/..
APP_DIR=`cd "${APP_DIR}"; pwd`
fi
executable="./modules/openapi-generator-cli/target/openapi-generator-cli.jar"
if [ ! -f "$executable" ]
then
mvn -B clean package
fi
# if you've executed sbt assembly previously it will use that instead.
export JAVA_OPTS="${JAVA_OPTS} -Xmx1024M -DloggerPath=conf/log4j.properties"
ags="generate -t modules/openapi-generator/src/main/resources/C-libcurl -i modules/openapi-generator/src/test/resources/2_0/petstore.yaml -g c -o samples/client/petstore/c $@"
java $JAVA_OPTS -jar $executable $ags

View File

@@ -0,0 +1,17 @@
#!/bin/sh
# C# Petstore API client (.NET 3.5)
./bin/csharp-refactor-petstore.sh
# C# Petstore API client with PropertyChanged
./bin/csharp-refactor-property-changed-petstore.sh
# C# Petstore API client (v5.0 for .net standarnd 1.3+)
./bin/csharp-refactor-petstore-net-standard.sh
# C# Petstore API client (.NET 4.0)
./bin/csharp-refactor-petstore-net-40.sh
# C# Petstore API client (.NET 3.5)
./bin/csharp-refactor-petstore-net-35.sh

37
bin/csharp-refactor-petstore.sh Executable file
View File

@@ -0,0 +1,37 @@
#!/bin/sh
SCRIPT="$0"
echo "# START SCRIPT: $SCRIPT"
while [ -h "$SCRIPT" ] ; do
ls=`ls -ld "$SCRIPT"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
SCRIPT="$link"
else
SCRIPT=`dirname "$SCRIPT"`/"$link"
fi
done
if [ ! -d "${APP_DIR}" ]; then
APP_DIR=`dirname "$SCRIPT"`/..
APP_DIR=`cd "${APP_DIR}"; pwd`
fi
executable="./modules/openapi-generator-cli/target/openapi-generator-cli.jar"
if [ ! -f "$executable" ]
then
mvn -B clean package
fi
# if you've executed sbt assembly previously it will use that instead.
export JAVA_OPTS="${JAVA_OPTS} -XX:MaxPermSize=256M -Xmx1024M -DloggerPath=conf/log4j.properties"
ags="generate -i modules/openapi-generator/src/test/resources/2_0/petstore-with-fake-endpoints-models-for-testing.yaml -g csharp-refactor -o samples/client/petstore/csharp-refactor/OpenAPIClient --additional-properties packageGuid={321C8C3F-0156-40C1-AE42-D59761FB9B6C} $@"
java $JAVA_OPTS -jar $executable $ags
# restore csproj file
#echo "restore csproject file: CI/samples/client/petstore/csharp/OpenAPIClient/src/Org.OpenAPITools.Test/Org.OpenAPITools.Test.csproj"
#cp ./CI/samples.ci/client/petstore/csharp/OpenAPIClient/src/Org.OpenAPITools.Test/Org.OpenAPITools.Test.csproj ./samples/client/petstore/csharp-refactor/OpenAPIClient/src/Org.OpenAPITools.Test/

View File

@@ -27,6 +27,6 @@ fi
# if you've executed sbt assembly previously it will use that instead.
export JAVA_OPTS="${JAVA_OPTS} -XX:MaxPermSize=256M -Xmx1024M -DloggerPath=conf/log4j.properties"
ags="generate -i modules/openapi-generator/src/test/resources/2_0/petstore.yaml -g cwiki -o samples/documentation/cwiki $@"
ags="generate -t modules/openapi-generator/src/main/resources/confluenceWikiDocs -i modules/openapi-generator/src/test/resources/2_0/petstore.yaml -g cwiki -o samples/documentation/cwiki $@"
java $JAVA_OPTS -jar $executable $ags

View File

@@ -27,6 +27,6 @@ fi
# if you've executed sbt assembly previously it will use that instead.
export JAVA_OPTS="${JAVA_OPTS} -XX:MaxPermSize=256M -Xmx1024M -DloggerPath=conf/log4j.properties"
ags="generate -i modules/openapi-generator/src/test/resources/2_0/petstore.yaml -g html -o samples/documentation/html $@"
ags="generate -t modules/openapi-generator/src/main/resources/htmlDocs -i modules/openapi-generator/src/test/resources/2_0/petstore.yaml -g html -o samples/documentation/html $@"
java $JAVA_OPTS -jar $executable $ags

0
bin/mysql-schema-petstore.sh Normal file → Executable file
View File

View File

@@ -25,8 +25,13 @@ then
mvn clean package
fi
# purge lib/doc folder
echo "purge ruby petstore lib, docs folder"
rm -Rf samples/openapi3/client/petstore/ruby/lib
rm -Rf samples/openapi3/client/petstore/ruby/docs
# if you've executed sbt assembly previously it will use that instead.
export JAVA_OPTS="${JAVA_OPTS} -XX:MaxPermSize=256M -Xmx1024M -DloggerPath=conf/log4j.properties"
ags="generate -t modules/openapi-generator/src/main/resources/ruby-client -i modules/openapi-generator/src/test/resources/3_0/petstore-with-fake-endpoints-models-for-testing.yaml -g ruby -c bin/ruby-petstore.json -o samples/client/petstore/ruby -DskipFormModel=true $@"
ags="generate -t modules/openapi-generator/src/main/resources/ruby-client -i modules/openapi-generator/src/test/resources/3_0/petstore-with-fake-endpoints-models-for-testing.yaml -g ruby -c bin/ruby-petstore.json -o samples/openapi3/client/petstore/ruby -DskipFormModel=true $@"
java $JAVA_OPTS -jar $executable $ags

0
bin/springboot-virtualan-petstore-server.sh Normal file → Executable file
View File

View File

@@ -27,6 +27,6 @@ fi
# if you've executed sbt assembly previously it will use that instead.
export JAVA_OPTS="${JAVA_OPTS} -XX:MaxPermSize=256M -Xmx1024M -DloggerPath=conf/log4j.properties"
ags="generate -i modules/openapi-generator/src/test\resources/2_0/petstore.yaml -g typescript-angular -c bin/typescript-angular-v6-petstore-not-provided-in-root-with-npm.json -o samples/client/petstore/typescript-angular-v6-not-provided-in-root/builds/with-npm -D providedInRoot=false --additional-properties ngVersion=6.0.0 $@"
ags="generate -i modules/openapi-generator/src/test/resources/2_0/petstore.yaml -g typescript-angular -c bin/typescript-angular-v6-petstore-not-provided-in-root-with-npm.json -o samples/client/petstore/typescript-angular-v6-not-provided-in-root/builds/with-npm -D providedInRoot=false --additional-properties ngVersion=6.0.0 $@"
java $JAVA_OPTS -jar $executable $ags

View File

@@ -27,6 +27,6 @@ fi
# if you've executed sbt assembly previously it will use that instead.
export JAVA_OPTS="${JAVA_OPTS} -XX:MaxPermSize=256M -Xmx1024M -DloggerPath=conf/log4j.properties"
ags="generate -i modules/openapi-generator/src/test\resources/2_0/petstore.yaml -g typescript-angular -o samples/client/petstore/typescript-angular-v6-not-provided-in-root/builds/default -D providedInRoot=false --additional-properties ngVersion=6.0.0 $@"
ags="generate -i modules/openapi-generator/src/test/resources/2_0/petstore.yaml -g typescript-angular -o samples/client/petstore/typescript-angular-v6-not-provided-in-root/builds/default -D providedInRoot=false --additional-properties ngVersion=6.0.0 $@"
java $JAVA_OPTS -jar $executable $ags

View File

@@ -10,34 +10,44 @@ echo "Please press CTRL+C to stop or the script will continue in 5 seconds."
sleep 5
# LIST OF SCRIPTS:
./bin/openapi3/ruby-client-petstore.sh > /dev/null 2>&1
./bin/java-petstore-all.sh > /dev/null 2>&1
./bin/java-jaxrs-petstore-server-all.sh > /dev/null 2>&1
./bin/openapi3/jaxrs-jersey-petstore.sh > /dev/null 2>&1
./bin/spring-all-pestore.sh > /dev/null 2>&1
./bin/kotlin-client-petstore.sh > /dev/null 2>&1
./bin/kotlin-client-string.sh > /dev/null 2>&1
./bin/kotlin-client-threetenbp.sh > /dev/null 2>&1
./bin/kotlin-server-petstore.sh > /dev/null 2>&1
./bin/mysql-schema-petstore.sh > /dev/null 2>&1
./bin/php-petstore.sh > /dev/null 2>&1
./bin/php-silex-petstore-server.sh > /dev/null 2>&1
./bin/php-symfony-petstore.sh > /dev/null 2>&1
./bin/php-lumen-petstore-server.sh > /dev/null 2>&1
./bin/php-slim-server-petstore.sh > /dev/null 2>&1
./bin/php-ze-ph-petstore-server.sh > /dev/null 2>&1
./bin/openapi3/php-petstore.sh > /dev/null 2>&1
./bin/typescript-angular-petstore-all.sh > /dev/null 2>&1
./bin/typescript-fetch-petstore-all.sh > /dev/null 2>&1
./bin/typescript-node-petstore-all.sh > /dev/null 2>&1
./bin/typescript-inversify-petstore.sh > /dev/null 2>&1
./bin/rust-server-petstore.sh > /dev/null 2>&1
./bin/haskell-http-client-petstore.sh > /dev/null 2>&1
./bin/csharp-petstore.sh > /dev/null 2>&1
./bin/meta-codegen.sh > /dev/null 2>&1
./bin/utils/export_docs_generators.sh > /dev/null 2>&1
./bin/go-petstore.sh > /dev/null 2>&1
./bin/go-gin-petstore-server.sh > /dev/null 2>&1
declare -a scripts=("./bin/openapi3/ruby-client-petstore.sh"
"./bin/ruby-client-petstore.sh"
"./bin/java-petstore-all.sh"
"./bin/java-jaxrs-petstore-server-all.sh"
"./bin/openapi3/jaxrs-jersey-petstore.sh"
"./bin/spring-all-pestore.sh"
"./bin/kotlin-client-petstore.sh"
"./bin/kotlin-client-string.sh"
"./bin/kotlin-client-threetenbp.sh"
"./bin/kotlin-server-petstore.sh"
"./bin/mysql-schema-petstore.sh"
"./bin/php-petstore.sh"
"./bin/php-silex-petstore-server.sh"
"./bin/php-symfony-petstore.sh"
"./bin/php-lumen-petstore-server.sh"
"./bin/php-slim-server-petstore.sh"
"./bin/php-ze-ph-petstore-server.sh"
"./bin/openapi3/php-petstore.sh"
"./bin/typescript-angular-petstore-all.sh"
"./bin/typescript-fetch-petstore-all.sh"
"./bin/typescript-node-petstore-all.sh"
"./bin/typescript-inversify-petstore.sh"
"./bin/rust-server-petstore.sh"
"./bin/haskell-http-client-petstore.sh"
"./bin/csharp-petstore.sh"
"./bin/meta-codegen.sh"
"./bin/utils/export_docs_generators.sh"
"./bin/go-petstore.sh"
"./bin/go-gin-petstore-server.sh")
for script in "${scripts[@]}"; do
if eval $script > /dev/null 2>&1; then
echo "Executed $script successfully!"
else
echo "ERROR: Failed to run $script"
exit 1
fi
done
# Check:
if [ -n "$(git status --porcelain)" ]; then

View File

@@ -0,0 +1,28 @@
#!/bin/bash
#
# A script to test all generators to ensure there's no Java exception when running it with OAS 2.0, 3.0 fake petstore spec
#
SCRIPT="$0"
echo "# START SCRIPT: ${SCRIPT}"
executable="./modules/openapi-generator-cli/target/openapi-generator-cli.jar"
for GENERATOR in $(java -jar ${executable} list --short | sed -e 's/,/\'$'\n''/g')
do
if eval java -jar ${executable} generate -i modules/openapi-generator/src/test/resources/2_0/petstore-with-fake-endpoints-models-for-testing.yaml -g ${GENERATOR} -o /tmp/openapi-generator-test-fake-petstore/2.0/${GENERATOR} > /dev/null 2>&1; then
echo "[OAS 2.0] Executed ${GENERATOR} successfully!"
else
echo "ERROR: Failed to run ${GENERATOR}"
echo "java -jar ${executable} generate -i modules/openapi-generator/src/test/resources/2_0/petstore-with-fake-endpoints-models-for-testing.yaml -g ${GENERATOR} -o /tmp/openapi-generator-test-fake-petstore/2.0/${GENERATOR}"
exit 1
fi
if eval java -jar ${executable} generate -i modules/openapi-generator/src/test/resources/2_0/petstore-with-fake-endpoints-models-for-testing.yaml -g ${GENERATOR} -o /tmp/openapi-generator-test-fake-petstore/3.0/${GENERATOR} > /dev/null 2>&1; then
echo "[OAS 3.0] Executed ${GENERATOR} successfully!"
else
echo "ERROR: Failed to run ${GENERATOR}"
echo "java -jar ${executable} generate -i modules/openapi-generator/src/test/resources/2_0/petstore-with-fake-endpoints-models-for-testing.yaml -g ${GENERATOR} -o /tmp/openapi-generator-test-fake-petstore/3.0/${GENERATOR}"
exit 1
fi
done

10
bin/windows/c-petstore.bat Executable file
View File

@@ -0,0 +1,10 @@
set executable=.\modules\openapi-generator-cli\target\openapi-generator-cli.jar
If Not Exist %executable% (
mvn clean package
)
REM set JAVA_OPTS=%JAVA_OPTS% -Xmx1024M
set ags=generate -i modules\openapi-generator\src\test\resources\2_0\petstore.yaml -g c -o samples\client\petstore\c
java %JAVA_OPTS% -jar %executable% %ags%

View File

@@ -19,6 +19,9 @@ CONFIG OPTIONS for kotlin-server
enumPropertyNaming
Naming convention for enum properties: 'camelCase', 'PascalCase', 'snake_case', 'UPPERCASE', and 'original' (Default: camelCase)
parcelizeModels
toggle "@Parcelize" for generated models
library
library template (sub-template) to use (Default: ktor)
ktor - ktor framework

View File

@@ -19,6 +19,9 @@ CONFIG OPTIONS for kotlin-spring
enumPropertyNaming
Naming convention for enum properties: 'camelCase', 'PascalCase', 'snake_case', 'UPPERCASE', and 'original' (Default: camelCase)
parcelizeModels
toggle "@Parcelize" for generated models
title
server title name or client service name (Default: OpenAPI Kotlin Spring)

View File

@@ -19,10 +19,18 @@ CONFIG OPTIONS for kotlin
enumPropertyNaming
Naming convention for enum properties: 'camelCase', 'PascalCase', 'snake_case', 'UPPERCASE', and 'original' (Default: camelCase)
parcelizeModels
toggle "@Parcelize" for generated models
dateLibrary
Option. Date library to use
string - String
java8 - Java 8 native JSR310
threetenbp - Threetenbp
collectionType
Option. Collection type to use
array - kotlin.Array
list - kotlin.collections.List
Back to the [generators list](README.md)

View File

@@ -5,6 +5,6 @@ CONFIG OPTIONS for rust-server
Rust crate name (convention: snake_case). (Default: openapi_client)
packageVersion
Rust crate version. (Default: 1.0.0)
Rust crate version.
Back to the [generators list](README.md)

View File

@@ -170,6 +170,9 @@ CONFIG OPTIONS for spring
hateoas
Use Spring HATEOAS library to allow adding HATEOAS links (Default: false)
returnSuccessCode
Generated server returns 2xx code (Default: false)
library
library template (sub-template) to use (Default: spring-boot)
spring-boot - Spring-boot Server application using the SpringFox integration.

View File

@@ -1,14 +1,25 @@
## Online OpenAPI generator
One can also generate API client or server using the online openapi-generator.
One can also generate API clients or server stubs using the online openapi-generator.
Here are the steps to run it locally:
Here are the public online services:
- latest stable version: http://api.openapi-generator.tech
- latest master: http://api-latest-master.openapi-generator.tech (updated with latest master every hour)
The server is sponsored by [Linode](https://www.linode.com/) [![Linode Logo](https://www.linode.com/media/images/logos/standard/light/linode-logo_standard_light_small.png)](https://www.linode.com/)
(These services are beta and do not have any guarantee on service level)
If you prefer to run the service locally, here are the steps:
```
mvn clean install
cd modules/openapi-generator-online
mvn spring-boot:run
```
:bulb: The online openapi-generator can be run via [Docker](https://github.com/OpenAPITools/openapi-generator#16---docker) as well.
For example, to generate Ruby API client, simply send the following HTTP request using curl:
```sh
curl -X POST -H "content-type:application/json" -d '{"openAPIUrl":"https://raw.githubusercontent.com/openapitools/openapi-generator/master/modules/openapi-generator/src/test/resources/2_0/petstore.yaml"}' http://localhost:8080/api/gen/clients/ruby

View File

@@ -1,7 +1,11 @@
FROM java:8-jre-alpine
ADD target/openapi-generator-cli.jar /opt/openapi-generator-cli/openapi-generator-cli.jar
RUN apk add --no-cache bash
ENTRYPOINT ["java", "-jar", "/opt/openapi-generator-cli/openapi-generator-cli.jar"]
ADD target/openapi-generator-cli.jar /opt/openapi-generator/modules/openapi-generator-cli/target/openapi-generator-cli.jar
CMD ["help"]
COPY docker-entrypoint.sh /usr/local/bin/
ENTRYPOINT ["docker-entrypoint.sh"]
CMD ["help"]

View File

@@ -3,7 +3,7 @@
<parent>
<groupId>org.openapitools</groupId>
<artifactId>openapi-generator-project</artifactId>
<version>3.3.2</version>
<version>3.3.4</version>
<relativePath>../..</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -32,6 +32,7 @@ import org.slf4j.LoggerFactory;
import static org.openapitools.codegen.config.CodegenConfiguratorUtils.*;
import static org.apache.commons.lang3.StringUtils.isNotEmpty;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Stream;
@@ -246,6 +247,11 @@ public class Generate implements Runnable {
}
if (isNotEmpty(spec)) {
if (!spec.matches("^http(s)?://.*") && !new File(spec).exists()) {
System.err.println("[error] The spec file is not found: " + spec);
System.err.println("[error] Check the path of the OpenAPI spec and try again.");
System.exit(1);
}
configurator.setInputSpec(spec);
}

View File

@@ -64,7 +64,7 @@ public class GenerateTest {
@Test
public void testRequiredArgs_ShortArgs() throws Exception {
setupAndRunTest("-i", "swagger.yaml", "-g", "java", "-o", "src/main/java", false, null);
setupAndRunTest("-i", "src/test/resources/swagger.yaml", "-g", "java", "-o", "src/main/java", false, null);
new FullVerifications() {
{
}
@@ -73,7 +73,7 @@ public class GenerateTest {
@Test
public void testRequiredArgs_LongArgs() throws Exception {
setupAndRunTest("--input-spec", "swagger.yaml", "--generator-name", "java", "--output",
setupAndRunTest("--input-spec", "src/test/resources/swagger.yaml", "--generator-name", "java", "--output",
"src/main/java", false, null);
new FullVerifications() {
{
@@ -220,7 +220,7 @@ public class GenerateTest {
@Test
public void testConfig() throws Exception {
setupAndRunTest("-i", "swagger.yaml", "-g", "java", "-o", "src/main/java", true,
setupAndRunTest("-i", "src/test/resources/swagger.yaml", "-g", "java", "-o", "src/main/java", true,
"config.json", "-c", "config.json");
new FullVerifications() {
@@ -228,7 +228,7 @@ public class GenerateTest {
}
};
setupAndRunTest("-i", "swagger.yaml", "-g", "java", "-o", "src/main/java", true,
setupAndRunTest("-i", "src/test/resources/swagger.yaml", "-g", "java", "-o", "src/main/java", true,
"config.json", "--config", "config.json");
new FullVerifications() {
@@ -570,7 +570,7 @@ public class GenerateTest {
}
private void setupAndRunGenericTest(String... additionalParameters) {
setupAndRunTest("-i", "swagger.yaml", "-g", "java", "-o", "src/main/java", false, null,
setupAndRunTest("-i", "src/test/resources/swagger.yaml", "-g", "java", "-o", "src/main/java", false, null,
additionalParameters);
}
}

View File

@@ -0,0 +1,109 @@
openapi: "3.0.0"
info:
version: 1.0.0
title: Swagger Petstore
license:
name: MIT
servers:
- url: http://petstore.swagger.io/v1
paths:
/pets:
get:
summary: List all pets
operationId: listPets
tags:
- pets
parameters:
- name: limit
in: query
description: How many items to return at one time (max 100)
required: false
schema:
type: integer
format: int32
responses:
'200':
description: A paged array of pets
headers:
x-next:
description: A link to the next page of responses
schema:
type: string
content:
application/json:
schema:
$ref: "#/components/schemas/Pets"
default:
description: unexpected error
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
post:
summary: Create a pet
operationId: createPets
tags:
- pets
responses:
'201':
description: Null response
default:
description: unexpected error
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
/pets/{petId}:
get:
summary: Info for a specific pet
operationId: showPetById
tags:
- pets
parameters:
- name: petId
in: path
required: true
description: The id of the pet to retrieve
schema:
type: string
responses:
'200':
description: Expected response to a valid request
content:
application/json:
schema:
$ref: "#/components/schemas/Pets"
default:
description: unexpected error
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
components:
schemas:
Pet:
required:
- id
- name
properties:
id:
type: integer
format: int64
name:
type: string
tag:
type: string
Pets:
type: array
items:
$ref: "#/components/schemas/Pet"
Error:
required:
- code
- message
properties:
code:
type: integer
format: int32
message:
type: string

View File

@@ -48,7 +48,7 @@ buildscript {
mavenCentral()
}
dependencies {
classpath "org.openapitools:openapi-generator-gradle-plugin:3.3.2"
classpath "org.openapitools:openapi-generator-gradle-plugin:3.3.4"
}
}
@@ -278,6 +278,32 @@ in others being disabled. That is, OpenAPI Generator considers any one of these
For more control over generation of individual files, configure an ignore file and refer to it via `ignoreFileOverride`.
====
[NOTE]
====
When configuring `systemProperties` in order to perform selective generation you can disable generation of some parts by providing `"false"` value:
[source,groovy]
----
openApiGenerate {
// other settings omitted
systemProperties = [
modelDocs: "false",
apis: "false"
]
}
----
When enabling generation of only specific parts you either have to provide CSV list of what you particularly are generating or provide an empty string `""` to generate everything. If you provide `"true"` it will be treated as a specific name of model or api you want to generate.
[source,groovy]
----
openApiGenerate {
// other settings omitted
systemProperties = [
apis: "",
models: "User,Pet"
]
}
----
====
=== openApiValidate
.Options

View File

@@ -1,4 +1,4 @@
openApiGeneratorVersion=3.3.2
openApiGeneratorVersion=3.3.4
# BEGIN placeholders
# these are just placeholders to allow contributors to build directly

View File

@@ -3,7 +3,7 @@
<parent>
<groupId>org.openapitools</groupId>
<artifactId>openapi-generator-project</artifactId>
<version>3.3.2</version>
<version>3.3.4</version>
<relativePath>../..</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -17,5 +17,5 @@ gradle generateGoWithInvalidSpec
The samples can be tested against other versions of the plugin using the `openApiGeneratorVersion` property. For example:
```bash
gradle -PopenApiGeneratorVersion=3.3.2 openApiValidate
gradle -PopenApiGeneratorVersion=3.3.4 openApiValidate
```

View File

@@ -1 +1 @@
openApiGeneratorVersion=3.3.2
openApiGeneratorVersion=3.3.4

View File

@@ -11,7 +11,7 @@ Add to your `build->plugins` section (default phase is `generate-sources` phase)
<plugin>
<groupId>org.openapitools</groupId>
<artifactId>openapi-generator-maven-plugin</artifactId>
<version>3.3.2</version>
<version>3.3.4</version>
<executions>
<execution>
<goals>

View File

@@ -12,7 +12,7 @@
<plugin>
<groupId>org.openapitools</groupId>
<artifactId>openapi-generator-maven-plugin</artifactId>
<version>3.3.2</version>
<version>3.3.4</version>
<executions>
<execution>
<goals>

View File

@@ -12,7 +12,7 @@
<plugin>
<groupId>org.openapitools</groupId>
<artifactId>openapi-generator-maven-plugin</artifactId>
<version>3.3.2</version>
<version>3.3.4</version>
<executions>
<execution>
<goals>

View File

@@ -12,7 +12,7 @@
<plugin>
<groupId>org.openapitools</groupId>
<artifactId>openapi-generator-maven-plugin</artifactId>
<version>3.3.2</version>
<version>3.3.4</version>
<executions>
<execution>
<goals>

View File

@@ -4,7 +4,7 @@
<parent>
<groupId>org.openapitools</groupId>
<artifactId>openapi-generator-project</artifactId>
<version>3.3.2</version>
<version>3.3.4</version>
<relativePath>../..</relativePath>
</parent>
<artifactId>openapi-generator-maven-plugin</artifactId>
@@ -15,6 +15,11 @@
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.sonatype.plexus</groupId>
<artifactId>plexus-build-api</artifactId>
<version>0.0.7</version>
</dependency>
<dependency>
<groupId>org.apache.maven</groupId>
<artifactId>maven-core</artifactId>

View File

@@ -42,6 +42,7 @@ import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugins.annotations.LifecyclePhase;
import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.plugins.annotations.Parameter;
import org.apache.maven.plugins.annotations.Component;
import org.apache.maven.project.MavenProject;
import org.openapitools.codegen.CliOption;
@@ -50,9 +51,15 @@ import org.openapitools.codegen.CodegenConfig;
import org.openapitools.codegen.CodegenConstants;
import org.openapitools.codegen.DefaultGenerator;
import org.openapitools.codegen.config.CodegenConfigurator;
import org.sonatype.plexus.build.incremental.BuildContext;
import org.sonatype.plexus.build.incremental.DefaultBuildContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.common.base.Charsets;
import com.google.common.hash.Hashing;
import com.google.common.io.Files;
/**
* Goal which generates client/server code from a OpenAPI json/yaml definition.
*/
@@ -61,6 +68,13 @@ public class CodeGenMojo extends AbstractMojo {
private static final Logger LOGGER = LoggerFactory.getLogger(CodeGenMojo.class);
/**
* The build context is only avail when running from within eclipse.
* It is used to update the eclipse-m2e-layer when the plugin is executed inside the IDE.
*/
@Component
private BuildContext buildContext = new DefaultBuildContext();
@Parameter(name="validateSpec", required = false, defaultValue = "true")
private Boolean validateSpec;
@@ -307,6 +321,12 @@ public class CodeGenMojo extends AbstractMojo {
@Parameter(name = "skip", property = "codegen.skip", required = false, defaultValue = "false")
private Boolean skip;
/**
* Skip the execution if the source file is older than the output folder.
*/
@Parameter(name = "skipIfSpecIsUnchanged", property = "codegen.skipIfSpecIsUnchanged", required = false, defaultValue = "false")
private Boolean skipIfSpecIsUnchanged;
/**
* Add the output directory to the project as a source root, so that the generated java types
* are compiled and included in the project artifact.
@@ -329,274 +349,330 @@ public class CodeGenMojo extends AbstractMojo {
@Parameter(readonly = true, required = true, defaultValue = "${project}")
private MavenProject project;
public void setBuildContext(BuildContext buildContext) {
this.buildContext = buildContext;
}
@Override
public void execute() throws MojoExecutionException {
File inputSpecFile = new File(inputSpec);
addCompileSourceRootIfConfigured();
if (skip) {
getLog().info("Code generation is skipped.");
// Even when no new sources are generated, the existing ones should
// still be compiled if needed.
addCompileSourceRootIfConfigured();
return;
}
// attempt to read from config file
CodegenConfigurator configurator = CodegenConfigurator.fromFile(configurationFile);
// if a config file wasn't specified or we were unable to read it
if (configurator == null) {
configurator = new CodegenConfigurator();
}
configurator.setVerbose(verbose);
// now override with any specified parameters
if (validateSpec != null) {
configurator.setValidateSpec(validateSpec);
}
if (skipOverwrite != null) {
configurator.setSkipOverwrite(skipOverwrite);
}
if (removeOperationIdPrefix != null) {
configurator.setRemoveOperationIdPrefix(removeOperationIdPrefix);
}
if (isNotEmpty(inputSpec)) {
configurator.setInputSpec(inputSpec);
}
if (isNotEmpty(gitUserId)) {
configurator.setGitUserId(gitUserId);
}
if (isNotEmpty(gitRepoId)) {
configurator.setGitRepoId(gitRepoId);
}
if (isNotEmpty(ignoreFileOverride)) {
configurator.setIgnoreFileOverride(ignoreFileOverride);
}
// TODO: After 3.0.0 release (maybe for 3.1.0): Fully deprecate lang.
if (isNotEmpty(generatorName)) {
configurator.setGeneratorName(generatorName);
// check if generatorName & language are set together, inform user this needs to be updated to prevent future issues.
if (isNotEmpty(language)) {
LOGGER.warn("The 'language' option is deprecated and was replaced by 'generatorName'. Both can not be set together");
throw new MojoExecutionException("Illegal configuration: 'language' and 'generatorName' can not be set both, remove 'language' from your configuration");
}
} else if (isNotEmpty(language)) {
LOGGER.warn("The 'language' option is deprecated and may reference language names only in the next major release (4.0). Please use 'generatorName' instead.");
configurator.setGeneratorName(language);
} else {
LOGGER.error("A generator name (generatorName) is required.");
throw new MojoExecutionException("The generator requires 'generatorName'. Refer to documentation for a list of options.");
}
configurator.setOutputDir(output.getAbsolutePath());
if (isNotEmpty(auth)) {
configurator.setAuth(auth);
}
if (isNotEmpty(apiPackage)) {
configurator.setApiPackage(apiPackage);
}
if (isNotEmpty(modelPackage)) {
configurator.setModelPackage(modelPackage);
}
if (isNotEmpty(invokerPackage)) {
configurator.setInvokerPackage(invokerPackage);
}
if (isNotEmpty(groupId)) {
configurator.setGroupId(groupId);
}
if (isNotEmpty(artifactId)) {
configurator.setArtifactId(artifactId);
}
if (isNotEmpty(artifactVersion)) {
configurator.setArtifactVersion(artifactVersion);
}
if (isNotEmpty(library)) {
configurator.setLibrary(library);
}
if (isNotEmpty(modelNamePrefix)) {
configurator.setModelNamePrefix(modelNamePrefix);
}
if (isNotEmpty(modelNameSuffix)) {
configurator.setModelNameSuffix(modelNameSuffix);
}
if (null != templateDirectory) {
configurator.setTemplateDir(templateDirectory.getAbsolutePath());
}
// Set generation options
if (null != generateApis && generateApis) {
System.setProperty(CodegenConstants.APIS, "");
} else {
System.clearProperty(CodegenConstants.APIS);
}
if (null != generateModels && generateModels) {
System.setProperty(CodegenConstants.MODELS, modelsToGenerate);
} else {
System.clearProperty(CodegenConstants.MODELS);
}
if (null != generateSupportingFiles && generateSupportingFiles) {
System.setProperty(CodegenConstants.SUPPORTING_FILES, supportingFilesToGenerate);
} else {
System.clearProperty(CodegenConstants.SUPPORTING_FILES);
}
System.setProperty(CodegenConstants.MODEL_TESTS, generateModelTests.toString());
System.setProperty(CodegenConstants.MODEL_DOCS, generateModelDocumentation.toString());
System.setProperty(CodegenConstants.API_TESTS, generateApiTests.toString());
System.setProperty(CodegenConstants.API_DOCS, generateApiDocumentation.toString());
System.setProperty(CodegenConstants.WITH_XML, withXml.toString());
if (configOptions != null) {
// Retained for backwards-compataibility with configOptions -> instantiation-types
if (instantiationTypes == null && configOptions.containsKey("instantiation-types")) {
applyInstantiationTypesKvp(configOptions.get("instantiation-types").toString(),
configurator);
}
// Retained for backwards-compataibility with configOptions -> import-mappings
if (importMappings == null && configOptions.containsKey("import-mappings")) {
applyImportMappingsKvp(configOptions.get("import-mappings").toString(),
configurator);
}
// Retained for backwards-compataibility with configOptions -> type-mappings
if (typeMappings == null && configOptions.containsKey("type-mappings")) {
applyTypeMappingsKvp(configOptions.get("type-mappings").toString(), configurator);
}
// Retained for backwards-compataibility with configOptions -> language-specific-primitives
if (languageSpecificPrimitives == null && configOptions.containsKey("language-specific-primitives")) {
applyLanguageSpecificPrimitivesCsv(configOptions
.get("language-specific-primitives").toString(), configurator);
}
// Retained for backwards-compataibility with configOptions -> additional-properties
if (additionalProperties == null && configOptions.containsKey("additional-properties")) {
applyAdditionalPropertiesKvp(configOptions.get("additional-properties").toString(),
configurator);
}
// Retained for backwards-compataibility with configOptions -> reserved-words-mappings
if (reservedWordsMappings == null && configOptions.containsKey("reserved-words-mappings")) {
applyReservedWordsMappingsKvp(configOptions.get("reserved-words-mappings")
.toString(), configurator);
}
}
//Apply Instantiation Types
if (instantiationTypes != null && (configOptions == null || !configOptions.containsKey("instantiation-types"))) {
applyInstantiationTypesKvpList(instantiationTypes, configurator);
}
//Apply Import Mappings
if (importMappings != null && (configOptions == null || !configOptions.containsKey("import-mappings"))) {
applyImportMappingsKvpList(importMappings, configurator);
}
//Apply Type Mappings
if (typeMappings != null && (configOptions == null || !configOptions.containsKey("type-mappings"))) {
applyTypeMappingsKvpList(typeMappings, configurator);
}
//Apply Language Specific Primitives
if (languageSpecificPrimitives != null && (configOptions == null || !configOptions.containsKey("language-specific-primitives"))) {
applyLanguageSpecificPrimitivesCsvList(languageSpecificPrimitives, configurator);
}
//Apply Additional Properties
if (additionalProperties != null && (configOptions == null || !configOptions.containsKey("additional-properties"))) {
applyAdditionalPropertiesKvpList(additionalProperties, configurator);
}
//Apply Reserved Words Mappings
if (reservedWordsMappings != null && (configOptions == null || !configOptions.containsKey("reserved-words-mappings"))) {
applyReservedWordsMappingsKvpList(reservedWordsMappings, configurator);
}
if (environmentVariables != null) {
for (String key : environmentVariables.keySet()) {
originalEnvironmentVariables.put(key, System.getProperty(key));
String value = environmentVariables.get(key);
if (value == null) {
// don't put null values
value = "";
}
System.setProperty(key, value);
configurator.addSystemProperty(key, value);
}
}
final ClientOptInput input = configurator.toClientOptInput();
final CodegenConfig config = input.getConfig();
if (configOptions != null) {
for (CliOption langCliOption : config.cliOptions()) {
if (configOptions.containsKey(langCliOption.getOpt())) {
input.getConfig().additionalProperties()
.put(langCliOption.getOpt(), configOptions.get(langCliOption.getOpt()));
}
}
}
if (configHelp) {
for (CliOption langCliOption : config.cliOptions()) {
System.out.println("\t" + langCliOption.getOpt());
System.out.println("\t "
+ langCliOption.getOptionHelp().replaceAll("\n", "\n\t "));
System.out.println();
}
return;
}
adjustAdditionalProperties(config);
try {
if (skip) {
getLog().info("Code generation is skipped.");
return;
}
if (buildContext != null) {
if (buildContext.isIncremental()) {
if (inputSpec != null) {
if (inputSpecFile.exists()) {
if (!buildContext.hasDelta(inputSpecFile)) {
getLog().info(
"Code generation is skipped in delta-build because source-json was not modified.");
return;
}
}
}
}
}
if (skipIfSpecIsUnchanged) {
if (inputSpecFile.exists()) {
File storedInputSpecHashFile = getHashFile(inputSpecFile);
if(storedInputSpecHashFile.exists()) {
String inputSpecHash = Files.asByteSource(inputSpecFile).hash(Hashing.sha256()).toString();
String storedInputSpecHash = Files.asCharSource(storedInputSpecHashFile, Charsets.UTF_8).read();
if (inputSpecHash.equals(storedInputSpecHash)) {
getLog().info(
"Code generation is skipped because input was unchanged");
return;
}
}
}
}
// attempt to read from config file
CodegenConfigurator configurator = CodegenConfigurator.fromFile(configurationFile);
// if a config file wasn't specified or we were unable to read it
if (configurator == null) {
configurator = new CodegenConfigurator();
}
configurator.setVerbose(verbose);
// now override with any specified parameters
if (validateSpec != null) {
configurator.setValidateSpec(validateSpec);
}
if (skipOverwrite != null) {
configurator.setSkipOverwrite(skipOverwrite);
}
if (removeOperationIdPrefix != null) {
configurator.setRemoveOperationIdPrefix(removeOperationIdPrefix);
}
if (isNotEmpty(inputSpec)) {
configurator.setInputSpec(inputSpec);
}
if (isNotEmpty(gitUserId)) {
configurator.setGitUserId(gitUserId);
}
if (isNotEmpty(gitRepoId)) {
configurator.setGitRepoId(gitRepoId);
}
if (isNotEmpty(ignoreFileOverride)) {
configurator.setIgnoreFileOverride(ignoreFileOverride);
}
// TODO: After 3.0.0 release (maybe for 3.1.0): Fully deprecate lang.
if (isNotEmpty(generatorName)) {
configurator.setGeneratorName(generatorName);
// check if generatorName & language are set together, inform user this needs to be updated to prevent future issues.
if (isNotEmpty(language)) {
LOGGER.warn("The 'language' option is deprecated and was replaced by 'generatorName'. Both can not be set together");
throw new MojoExecutionException(
"Illegal configuration: 'language' and 'generatorName' can not be set both, remove 'language' from your configuration");
}
} else if (isNotEmpty(language)) {
LOGGER.warn(
"The 'language' option is deprecated and may reference language names only in the next major release (4.0). Please use 'generatorName' instead.");
configurator.setGeneratorName(language);
} else {
LOGGER.error("A generator name (generatorName) is required.");
throw new MojoExecutionException("The generator requires 'generatorName'. Refer to documentation for a list of options.");
}
configurator.setOutputDir(output.getAbsolutePath());
if (isNotEmpty(auth)) {
configurator.setAuth(auth);
}
if (isNotEmpty(apiPackage)) {
configurator.setApiPackage(apiPackage);
}
if (isNotEmpty(modelPackage)) {
configurator.setModelPackage(modelPackage);
}
if (isNotEmpty(invokerPackage)) {
configurator.setInvokerPackage(invokerPackage);
}
if (isNotEmpty(groupId)) {
configurator.setGroupId(groupId);
}
if (isNotEmpty(artifactId)) {
configurator.setArtifactId(artifactId);
}
if (isNotEmpty(artifactVersion)) {
configurator.setArtifactVersion(artifactVersion);
}
if (isNotEmpty(library)) {
configurator.setLibrary(library);
}
if (isNotEmpty(modelNamePrefix)) {
configurator.setModelNamePrefix(modelNamePrefix);
}
if (isNotEmpty(modelNameSuffix)) {
configurator.setModelNameSuffix(modelNameSuffix);
}
if (null != templateDirectory) {
configurator.setTemplateDir(templateDirectory.getAbsolutePath());
}
// Set generation options
if (null != generateApis && generateApis) {
System.setProperty(CodegenConstants.APIS, "");
} else {
System.clearProperty(CodegenConstants.APIS);
}
if (null != generateModels && generateModels) {
System.setProperty(CodegenConstants.MODELS, modelsToGenerate);
} else {
System.clearProperty(CodegenConstants.MODELS);
}
if (null != generateSupportingFiles && generateSupportingFiles) {
System.setProperty(CodegenConstants.SUPPORTING_FILES, supportingFilesToGenerate);
} else {
System.clearProperty(CodegenConstants.SUPPORTING_FILES);
}
System.setProperty(CodegenConstants.MODEL_TESTS, generateModelTests.toString());
System.setProperty(CodegenConstants.MODEL_DOCS, generateModelDocumentation.toString());
System.setProperty(CodegenConstants.API_TESTS, generateApiTests.toString());
System.setProperty(CodegenConstants.API_DOCS, generateApiDocumentation.toString());
System.setProperty(CodegenConstants.WITH_XML, withXml.toString());
if (configOptions != null) {
// Retained for backwards-compataibility with configOptions -> instantiation-types
if (instantiationTypes == null && configOptions.containsKey("instantiation-types")) {
applyInstantiationTypesKvp(configOptions.get("instantiation-types").toString(),
configurator);
}
// Retained for backwards-compataibility with configOptions -> import-mappings
if (importMappings == null && configOptions.containsKey("import-mappings")) {
applyImportMappingsKvp(configOptions.get("import-mappings").toString(),
configurator);
}
// Retained for backwards-compataibility with configOptions -> type-mappings
if (typeMappings == null && configOptions.containsKey("type-mappings")) {
applyTypeMappingsKvp(configOptions.get("type-mappings").toString(), configurator);
}
// Retained for backwards-compataibility with configOptions -> language-specific-primitives
if (languageSpecificPrimitives == null && configOptions.containsKey("language-specific-primitives")) {
applyLanguageSpecificPrimitivesCsv(configOptions
.get("language-specific-primitives").toString(), configurator);
}
// Retained for backwards-compataibility with configOptions -> additional-properties
if (additionalProperties == null && configOptions.containsKey("additional-properties")) {
applyAdditionalPropertiesKvp(configOptions.get("additional-properties").toString(),
configurator);
}
// Retained for backwards-compataibility with configOptions -> reserved-words-mappings
if (reservedWordsMappings == null && configOptions.containsKey("reserved-words-mappings")) {
applyReservedWordsMappingsKvp(configOptions.get("reserved-words-mappings")
.toString(), configurator);
}
}
// Apply Instantiation Types
if (instantiationTypes != null && (configOptions == null || !configOptions.containsKey("instantiation-types"))) {
applyInstantiationTypesKvpList(instantiationTypes, configurator);
}
// Apply Import Mappings
if (importMappings != null && (configOptions == null || !configOptions.containsKey("import-mappings"))) {
applyImportMappingsKvpList(importMappings, configurator);
}
// Apply Type Mappings
if (typeMappings != null && (configOptions == null || !configOptions.containsKey("type-mappings"))) {
applyTypeMappingsKvpList(typeMappings, configurator);
}
// Apply Language Specific Primitives
if (languageSpecificPrimitives != null
&& (configOptions == null || !configOptions.containsKey("language-specific-primitives"))) {
applyLanguageSpecificPrimitivesCsvList(languageSpecificPrimitives, configurator);
}
// Apply Additional Properties
if (additionalProperties != null && (configOptions == null || !configOptions.containsKey("additional-properties"))) {
applyAdditionalPropertiesKvpList(additionalProperties, configurator);
}
// Apply Reserved Words Mappings
if (reservedWordsMappings != null && (configOptions == null || !configOptions.containsKey("reserved-words-mappings"))) {
applyReservedWordsMappingsKvpList(reservedWordsMappings, configurator);
}
if (environmentVariables != null) {
for (String key : environmentVariables.keySet()) {
originalEnvironmentVariables.put(key, System.getProperty(key));
String value = environmentVariables.get(key);
if (value == null) {
// don't put null values
value = "";
}
System.setProperty(key, value);
configurator.addSystemProperty(key, value);
}
}
final ClientOptInput input = configurator.toClientOptInput();
final CodegenConfig config = input.getConfig();
if (configOptions != null) {
for (CliOption langCliOption : config.cliOptions()) {
if (configOptions.containsKey(langCliOption.getOpt())) {
input.getConfig().additionalProperties()
.put(langCliOption.getOpt(), configOptions.get(langCliOption.getOpt()));
}
}
}
if (configHelp) {
for (CliOption langCliOption : config.cliOptions()) {
System.out.println("\t" + langCliOption.getOpt());
System.out.println("\t "
+ langCliOption.getOptionHelp().replaceAll("\n", "\n\t "));
System.out.println();
}
return;
}
adjustAdditionalProperties(config);
new DefaultGenerator().opts(input).generate();
if (buildContext != null) {
buildContext.refresh(new File(getCompileSourceRoot()));
}
// Store a checksum of the input spec
File storedInputSpecHashFile = getHashFile(inputSpecFile);
String inputSpecHash = Files.asByteSource(inputSpecFile).hash(Hashing.sha256()).toString();
if (storedInputSpecHashFile.getParent() != null && !new File(storedInputSpecHashFile.getParent()).exists()) {
File parent = new File(storedInputSpecHashFile.getParent());
parent.mkdirs();
}
Files.asCharSink(storedInputSpecHashFile, Charsets.UTF_8).write(inputSpecHash);
} catch (Exception e) {
// Maven logs exceptions thrown by plugins only if invoked with -e
// I find it annoying to jump through hoops to get basic diagnostic information,
// so let's log it in any case:
if (buildContext != null) {
buildContext.addError(inputSpecFile, 0, 0, "unexpected error in Open-API generation", e);
}
getLog().error(e);
throw new MojoExecutionException(
"Code generation failed. See above for the full exception.");
}
}
addCompileSourceRootIfConfigured();
private File getHashFile(File inputSpecFile) {
return new File(output.getPath() + File.separator + ".openapi-generator" + File.separator + inputSpecFile.getName() + ".sha256");
}
private String getCompileSourceRoot() {
final Object sourceFolderObject =
configOptions == null ? null : configOptions
.get(CodegenConstants.SOURCE_FOLDER);
final String sourceFolder =
sourceFolderObject == null ? "src/main/java" : sourceFolderObject.toString();
String sourceJavaFolder = output.toString() + "/" + sourceFolder;
return sourceJavaFolder;
}
private void addCompileSourceRootIfConfigured() {
if (addCompileSourceRoot) {
final Object sourceFolderObject =
configOptions == null ? null : configOptions
.get(CodegenConstants.SOURCE_FOLDER);
final String sourceFolder =
sourceFolderObject == null ? "src/main/java" : sourceFolderObject.toString();
String sourceJavaFolder = output.toString() + "/" + sourceFolder;
project.addCompileSourceRoot(sourceJavaFolder);
project.addCompileSourceRoot(getCompileSourceRoot());
}
// Reset all environment variables to their original value. This prevents unexpected
@@ -611,10 +687,10 @@ public class CodeGenMojo extends AbstractMojo {
}
}
/**
* This method enables conversion of true/false strings in
* This method enables conversion of true/false strings in
* config.additionalProperties (configuration/configOptions) to proper booleans.
* This enables mustache files to handle the properties better.
*
*
* @param config
*/
private void adjustAdditionalProperties(final CodegenConfig config) {

View File

@@ -0,0 +1,17 @@
<lifecycleMappingMetadata>
<pluginExecutions>
<pluginExecution>
<pluginExecutionFilter>
<goals>
<goal>generate</goal>
</goals>
</pluginExecutionFilter>
<action>
<execute>
<runOnIncremental>true</runOnIncremental>
<runOnConfiguration>true</runOnConfiguration>
</execute>
</action>
</pluginExecution>
</pluginExecutions>
</lifecycleMappingMetadata>

View File

@@ -3,7 +3,7 @@
<parent>
<groupId>org.openapitools</groupId>
<artifactId>openapi-generator-project</artifactId>
<version>3.3.2</version>
<version>3.3.4</version>
<relativePath>../..</relativePath>
</parent>
<artifactId>openapi-generator-online</artifactId>

View File

@@ -19,11 +19,11 @@ package org.openapitools.codegen.online.service;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;
import org.openapitools.codegen.online.api.GenApiDelegate;
import org.openapitools.codegen.CliOption;
import org.openapitools.codegen.CodegenConfig;
import org.openapitools.codegen.CodegenConfigLoader;
import org.openapitools.codegen.CodegenType;
import org.openapitools.codegen.online.api.GenApiDelegate;
import org.openapitools.codegen.online.model.Generated;
import org.openapitools.codegen.online.model.GeneratorInput;
import org.openapitools.codegen.online.model.ResponseCode;
@@ -36,8 +36,9 @@ import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.server.ResponseStatusException;
import org.springframework.web.servlet.support.ServletUriComponentsBuilder;
import org.springframework.web.util.UriComponentsBuilder;
import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
@@ -114,33 +115,7 @@ public class GenApiService implements GenApiDelegate {
@Override
public ResponseEntity<ResponseCode> generateClient(String language, GeneratorInput generatorInput) {
String filename = Generator.generateClient(language, generatorInput);
String host = System.getenv("GENERATOR_HOST");
HttpServletRequest servletRequest = request.getNativeRequest(HttpServletRequest.class);
if (StringUtils.isBlank(host)) {
String scheme = servletRequest.getHeader("X-SSL");
String port = "";
if ("1".equals(scheme)) {
scheme = "https";
} else {
scheme = servletRequest.getScheme();
port = ":" + servletRequest.getServerPort();
}
host = scheme + "://" + servletRequest.getServerName() + port;
}
if (filename != null) {
String code = String.valueOf(UUID.randomUUID().toString());
Generated g = new Generated();
g.setFilename(filename);
g.setFriendlyName(language + "-client");
fileMap.put(code, g);
System.out.println(code + ", " + filename);
String link = host + "/api/gen/download/" + code;
return ResponseEntity.ok().body(new ResponseCode(code, link));
} else {
return ResponseEntity.status(500).build();
}
return getResponse(filename, language + "-client");
}
@Override
@@ -183,20 +158,27 @@ public class GenApiService implements GenApiDelegate {
String filename = Generator.generateServer(framework, generatorInput);
System.out.println("generated name: " + filename);
HttpServletRequest servletRequest = request.getNativeRequest(HttpServletRequest.class);
return getResponse(filename, framework + "-server");
}
String host =
servletRequest.getScheme() + "://" + servletRequest.getServerName() + ":"
+ servletRequest.getServerPort();
private ResponseEntity<ResponseCode> getResponse(String filename, String friendlyName) {
String host = System.getenv("GENERATOR_HOST");
UriComponentsBuilder uriBuilder;
if (!StringUtils.isBlank(host)) {
uriBuilder = UriComponentsBuilder.fromUriString(host);
} else {
uriBuilder = ServletUriComponentsBuilder.fromCurrentContextPath();
}
if (filename != null) {
String code = String.valueOf(UUID.randomUUID().toString());
String code = UUID.randomUUID().toString();
Generated g = new Generated();
g.setFilename(filename);
g.setFriendlyName(framework + "-server");
g.setFriendlyName(friendlyName);
fileMap.put(code, g);
System.out.println(code + ", " + filename);
String link = host + "/api/gen/download/" + code;
String link = uriBuilder.path("/api/gen/download/").path(code).toUriString();
return ResponseEntity.ok().body(new ResponseCode(code, link));
} else {
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();

View File

@@ -3,7 +3,7 @@
<parent>
<groupId>org.openapitools</groupId>
<artifactId>openapi-generator-project</artifactId>
<version>3.3.2</version>
<version>3.3.4</version>
<relativePath>../..</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -27,6 +27,7 @@ import io.swagger.v3.oas.models.servers.Server;
import io.swagger.v3.oas.models.servers.ServerVariable;
import java.io.File;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -261,4 +262,9 @@ public interface CodegenConfig {
public void setEnablePostProcessFile(boolean isEnablePostProcessFile);
// set OpenAPI and schemas
public void setGlobalOpenAPI(OpenAPI openAPI);
public void setGlobalSchemas(OpenAPI openAPI);
}

View File

@@ -221,6 +221,10 @@ public class CodegenConstants {
public static final String SOURCECODEONLY_GENERATION = "generateSourceCodeOnly";
public static final String SOURCECODEONLY_GENERATION_DESC = "Specifies that only a library source code is to be generated.";
public static final String PARCELIZE_MODELS = "parcelizeModels";
public static final String PARCELIZE_MODELS_DESC = "toggle \"@Parcelize\" for generated models";
// Not user-configurable. System provided for use in templates.
public static final String GENERATE_APIS = "generateApis";

View File

@@ -27,11 +27,12 @@ public class CodegenParameter {
isCookieParam, isBodyParam, hasMore, isContainer,
secondaryParam, isCollectionFormatMulti, isPrimitiveType, isModel;
public String baseName, paramName, dataType, datatypeWithEnum, dataFormat,
collectionFormat, description, unescapedDescription, baseType, defaultValue, enumName;
collectionFormat, description, unescapedDescription, baseType, defaultValue, enumName;
public String example; // example value (x-example)
public String jsonSchema;
public boolean isString, isNumeric, isInteger, isLong, isNumber, isFloat, isDouble, isByteArray, isBinary, isBoolean, isDate, isDateTime, isUuid, isEmail;
public boolean isString, isNumeric, isInteger, isLong, isNumber, isFloat, isDouble, isByteArray, isBinary,
isBoolean, isDate, isDateTime, isUuid, isEmail, isFreeFormObject;
public boolean isListContainer, isMapContainer;
public boolean isFile;
public boolean isEnum;
@@ -94,7 +95,7 @@ public class CodegenParameter {
* See http://json-schema.org/latest/json-schema-validation.html#anchor14
*/
public Number multipleOf;
public CodegenParameter copy() {
CodegenParameter output = new CodegenParameter();
output.isFile = this.isFile;
@@ -148,7 +149,7 @@ public class CodegenParameter {
if (this.mostInnerItems != null) {
output.mostInnerItems = this.mostInnerItems;
}
if(this.vendorExtensions != null){
if (this.vendorExtensions != null) {
output.vendorExtensions = new HashMap<String, Object>(this.vendorExtensions);
}
output.hasValidation = this.hasValidation;
@@ -167,6 +168,7 @@ public class CodegenParameter {
output.isDateTime = this.isDateTime;
output.isUuid = this.isUuid;
output.isEmail = this.isEmail;
output.isFreeFormObject = this.isFreeFormObject;
output.isListContainer = this.isListContainer;
output.isMapContainer = this.isMapContainer;
@@ -259,6 +261,8 @@ public class CodegenParameter {
return false;
if (isEmail != that.isEmail)
return false;
if (isFreeFormObject != that.isFreeFormObject)
return false;
if (isListContainer != that.isListContainer)
return false;
if (isMapContainer != that.isMapContainer)
@@ -307,18 +311,18 @@ public class CodegenParameter {
@Override
public int hashCode() {
int result = isFormParam ? 13:31;
result = 31 * result + (isQueryParam ? 13:31);
result = 31 * result + (isPathParam ? 13:31);
result = 31 * result + (isHeaderParam ? 13:31);
result = 31 * result + (isCookieParam ? 13:31);
result = 31 * result + (isBodyParam ? 13:31);
result = 31 * result + (hasMore ? 13:31);
result = 31 * result + (isContainer ? 13:31);
result = 31 * result + (secondaryParam ? 13:31);
result = 31 * result + (isCollectionFormatMulti ? 13:31);
result = 31 * result + (isPrimitiveType ? 13:31);
result = 31 * result + (isModel ? 13:31);
int result = isFormParam ? 13 : 31;
result = 31 * result + (isQueryParam ? 13 : 31);
result = 31 * result + (isPathParam ? 13 : 31);
result = 31 * result + (isHeaderParam ? 13 : 31);
result = 31 * result + (isCookieParam ? 13 : 31);
result = 31 * result + (isBodyParam ? 13 : 31);
result = 31 * result + (hasMore ? 13 : 31);
result = 31 * result + (isContainer ? 13 : 31);
result = 31 * result + (secondaryParam ? 13 : 31);
result = 31 * result + (isCollectionFormatMulti ? 13 : 31);
result = 31 * result + (isPrimitiveType ? 13 : 31);
result = 31 * result + (isModel ? 13 : 31);
result = 31 * result + (baseName != null ? baseName.hashCode() : 0);
result = 31 * result + (paramName != null ? paramName.hashCode() : 0);
result = 31 * result + (dataType != null ? dataType.hashCode() : 0);
@@ -332,42 +336,43 @@ public class CodegenParameter {
result = 31 * result + (defaultValue != null ? defaultValue.hashCode() : 0);
result = 31 * result + (example != null ? example.hashCode() : 0);
result = 31 * result + (jsonSchema != null ? jsonSchema.hashCode() : 0);
result = 31 * result + (isString ? 13:31);
result = 31 * result + (isNumeric ? 13:31);
result = 31 * result + (isInteger ? 13:31);
result = 31 * result + (isLong ? 13:31);
result = 31 * result + (isFloat ? 13:31);
result = 31 * result + (isNumber ? 13:31);
result = 31 * result + (isDouble ? 13:31);
result = 31 * result + (isByteArray ? 13:31);
result = 31 * result + (isBinary ? 13:31);
result = 31 * result + (isBoolean ? 13:31);
result = 31 * result + (isDate ? 13:31);
result = 31 * result + (isDateTime ? 13:31);
result = 31 * result + (isUuid ? 13:31);
result = 31 * result + (isEmail ? 13:31);
result = 31 * result + (isListContainer ? 13:31);
result = 31 * result + (isMapContainer ? 13:31);
result = 31 * result + (isFile ? 13:31);
result = 31 * result + (isString ? 13 : 31);
result = 31 * result + (isNumeric ? 13 : 31);
result = 31 * result + (isInteger ? 13 : 31);
result = 31 * result + (isLong ? 13 : 31);
result = 31 * result + (isFloat ? 13 : 31);
result = 31 * result + (isNumber ? 13 : 31);
result = 31 * result + (isDouble ? 13 : 31);
result = 31 * result + (isByteArray ? 13 : 31);
result = 31 * result + (isBinary ? 13 : 31);
result = 31 * result + (isBoolean ? 13 : 31);
result = 31 * result + (isDate ? 13 : 31);
result = 31 * result + (isDateTime ? 13 : 31);
result = 31 * result + (isUuid ? 13 : 31);
result = 31 * result + (isEmail ? 13 : 31);
result = 31 * result + (isFreeFormObject ? 13 : 31);
result = 31 * result + (isListContainer ? 13 : 31);
result = 31 * result + (isMapContainer ? 13 : 31);
result = 31 * result + (isFile ? 13 : 31);
result = 31 * result + (isEnum ? 1 : 0);
result = 31 * result + (_enum != null ? _enum.hashCode() : 0);
result = 31 * result + (allowableValues != null ? allowableValues.hashCode() : 0);
result = 31 * result + (items != null ? items.hashCode() : 0);
result = 31 * result + (mostInnerItems != null ? mostInnerItems.hashCode() : 0);
result = 31 * result + (vendorExtensions != null ? vendorExtensions.hashCode() : 0);
result = 31 * result + (hasValidation ? 13:31);
result = 31 * result + (isNullable ? 13:31);
result = 31 * result + (required ? 13:31);
result = 31 * result + (hasValidation ? 13 : 31);
result = 31 * result + (isNullable ? 13 : 31);
result = 31 * result + (required ? 13 : 31);
result = 31 * result + (maximum != null ? maximum.hashCode() : 0);
result = 31 * result + (exclusiveMaximum ? 13:31);
result = 31 * result + (exclusiveMaximum ? 13 : 31);
result = 31 * result + (minimum != null ? minimum.hashCode() : 0);
result = 31 * result + (exclusiveMinimum ? 13:31);
result = 31 * result + (exclusiveMinimum ? 13 : 31);
result = 31 * result + (maxLength != null ? maxLength.hashCode() : 0);
result = 31 * result + (minLength != null ? minLength.hashCode() : 0);
result = 31 * result + (pattern != null ? pattern.hashCode() : 0);
result = 31 * result + (maxItems != null ? maxItems.hashCode() : 0);
result = 31 * result + (minItems != null ? minItems.hashCode() : 0);
result = 31 * result + (uniqueItems ? 13:31);
result = 31 * result + (uniqueItems ? 13 : 31);
result = 31 * result + (multipleOf != null ? multipleOf.hashCode() : 0);
return result;
}
@@ -414,6 +419,7 @@ public class CodegenParameter {
", isDateTime=" + isDateTime +
", isUuid=" + isUuid +
", isEmail=" + isEmail +
", isFreeFormObject=" + isFreeFormObject +
", isListContainer=" + isListContainer +
", isMapContainer=" + isMapContainer +
", isFile=" + isFile +

View File

@@ -25,10 +25,12 @@ import java.util.Objects;
public class CodegenProperty implements Cloneable {
public String baseName, complexType, getter, setter, description, dataType,
datatypeWithEnum, dataFormat, name, min, max, defaultValue, defaultValueWithParam,
baseType, containerType, title;
datatypeWithEnum, dataFormat, name, min, max, defaultValue, defaultValueWithParam,
baseType, containerType, title;
/** The 'description' string without escape charcters needed by some programming languages/targets */
/**
* The 'description' string without escape charcters needed by some programming languages/targets
*/
public String unescapedDescription;
/**
@@ -56,7 +58,8 @@ public class CodegenProperty implements Cloneable {
public boolean hasMore, required, secondaryParam;
public boolean hasMoreNonReadOnly; // for model constructor, true if next property is not readonly
public boolean isPrimitiveType, isModel, isContainer, isNotContainer;
public boolean isString, isNumeric, isInteger, isLong, isNumber, isFloat, isDouble, isByteArray, isBinary, isFile, isBoolean, isDate, isDateTime, isUuid, isEmail;
public boolean isString, isNumeric, isInteger, isLong, isNumber, isFloat, isDouble, isByteArray, isBinary, isFile,
isBoolean, isDate, isDateTime, isUuid, isEmail, isFreeFormObject;
public boolean isListContainer, isMapContainer;
public boolean isEnum;
public boolean isReadOnly;
@@ -84,7 +87,7 @@ public class CodegenProperty implements Cloneable {
public String xmlNamespace;
public boolean isXmlWrapped = false;
public String getBaseName() {
public String getBaseName() {
return baseName;
}
@@ -125,9 +128,9 @@ public class CodegenProperty implements Cloneable {
}
/**
* @return dataType
* @deprecated since version 3.0.0, use {@link #getDataType()} instead.<br>
* May be removed with the next major release (4.0)
* @return dataType
*/
@Deprecated
public String getDatatype() {
@@ -411,8 +414,7 @@ public class CodegenProperty implements Cloneable {
}
@Override
public int hashCode()
{
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((_enum == null) ? 0 : _enum.hashCode());
@@ -429,19 +431,19 @@ public class CodegenProperty implements Cloneable {
result = prime * result + ((description == null) ? 0 : description.hashCode());
result = prime * result + ((title == null) ? 0 : title.hashCode());
result = prime * result + ((example == null) ? 0 : example.hashCode());
result = prime * result + (exclusiveMaximum ? 13:31);
result = prime * result + (exclusiveMinimum ? 13:31);
result = prime * result + (exclusiveMaximum ? 13 : 31);
result = prime * result + (exclusiveMinimum ? 13 : 31);
result = prime * result + ((getter == null) ? 0 : getter.hashCode());
result = prime * result + (hasMore ? 13:31);
result = prime * result + ((hasMoreNonReadOnly ? 13:31));
result = prime * result + ((isContainer ? 13:31));
result = prime * result + (hasMore ? 13 : 31);
result = prime * result + ((hasMoreNonReadOnly ? 13 : 31));
result = prime * result + ((isContainer ? 13 : 31));
result = prime * result + (isEnum ? 1231 : 1237);
result = prime * result + ((isNotContainer ? 13:31));
result = prime * result + ((isPrimitiveType ? 13:31));
result = prime * result + ((isModel ? 13:31));
result = prime * result + ((isReadOnly ? 13:31));
result = prime * result + ((isWriteOnly ? 13:31));
result = prime * result + ((isNullable ? 13:31));
result = prime * result + ((isNotContainer ? 13 : 31));
result = prime * result + ((isPrimitiveType ? 13 : 31));
result = prime * result + ((isModel ? 13 : 31));
result = prime * result + ((isReadOnly ? 13 : 31));
result = prime * result + ((isWriteOnly ? 13 : 31));
result = prime * result + ((isNullable ? 13 : 31));
result = prime * result + ((items == null) ? 0 : items.hashCode());
result = prime * result + ((mostInnerItems == null) ? 0 : mostInnerItems.hashCode());
result = prime * result + ((jsonSchema == null) ? 0 : jsonSchema.hashCode());
@@ -453,29 +455,30 @@ public class CodegenProperty implements Cloneable {
result = prime * result + ((minimum == null) ? 0 : minimum.hashCode());
result = prime * result + ((name == null) ? 0 : name.hashCode());
result = prime * result + ((pattern == null) ? 0 : pattern.hashCode());
result = prime * result + ((required ? 13:31));
result = prime * result + ((secondaryParam ? 13:31));
result = prime * result + ((required ? 13 : 31));
result = prime * result + ((secondaryParam ? 13 : 31));
result = prime * result + ((setter == null) ? 0 : setter.hashCode());
result = prime * result + ((unescapedDescription == null) ? 0 : unescapedDescription.hashCode());
result = prime * result + ((vendorExtensions == null) ? 0 : vendorExtensions.hashCode());
result = prime * result + ((hasValidation ? 13:31));
result = prime * result + ((isString ? 13:31));
result = prime * result + ((isNumeric ? 13:31));
result = prime * result + ((isInteger ? 13:31));
result = prime * result + ((isLong ?13:31));
result = prime * result + ((isNumber ? 13:31));
result = prime * result + ((isFloat ? 13:31));
result = prime * result + ((isDouble ? 13:31));
result = prime * result + ((isByteArray ? 13:31));
result = prime * result + ((isBinary ? 13:31));
result = prime * result + ((isFile ? 13:31));
result = prime * result + ((isBoolean ? 13:31));
result = prime * result + ((isDate ? 13:31));
result = prime * result + ((isDateTime ? 13:31));
result = prime * result + ((isUuid ? 13:31));
result = prime * result + ((isEmail ? 13:31));
result = prime * result + ((isMapContainer ? 13:31));
result = prime * result + ((isListContainer ? 13:31));
result = prime * result + ((hasValidation ? 13 : 31));
result = prime * result + ((isString ? 13 : 31));
result = prime * result + ((isNumeric ? 13 : 31));
result = prime * result + ((isInteger ? 13 : 31));
result = prime * result + ((isLong ? 13 : 31));
result = prime * result + ((isNumber ? 13 : 31));
result = prime * result + ((isFloat ? 13 : 31));
result = prime * result + ((isDouble ? 13 : 31));
result = prime * result + ((isByteArray ? 13 : 31));
result = prime * result + ((isBinary ? 13 : 31));
result = prime * result + ((isFile ? 13 : 31));
result = prime * result + ((isBoolean ? 13 : 31));
result = prime * result + ((isDate ? 13 : 31));
result = prime * result + ((isDateTime ? 13 : 31));
result = prime * result + ((isUuid ? 13 : 31));
result = prime * result + ((isEmail ? 13 : 31));
result = prime * result + ((isFreeFormObject ? 13 : 31));
result = prime * result + ((isMapContainer ? 13 : 31));
result = prime * result + ((isListContainer ? 13 : 31));
result = prime * result + Objects.hashCode(isInherited);
result = prime * result + Objects.hashCode(discriminatorValue);
result = prime * result + Objects.hashCode(nameInCamelCase);
@@ -483,11 +486,11 @@ public class CodegenProperty implements Cloneable {
result = prime * result + Objects.hashCode(enumName);
result = prime * result + ((maxItems == null) ? 0 : maxItems.hashCode());
result = prime * result + ((minItems == null) ? 0 : minItems.hashCode());
result = prime * result + ((isXmlAttribute ? 13:31));
result = prime * result + ((isXmlAttribute ? 13 : 31));
result = prime * result + ((xmlPrefix == null) ? 0 : xmlPrefix.hashCode());
result = prime * result + ((xmlName == null) ? 0 : xmlName.hashCode());
result = prime * result + ((xmlNamespace == null) ? 0 : xmlNamespace.hashCode());
result = prime * result + ((isXmlWrapped ? 13:31));
result = prime * result + ((isXmlWrapped ? 13 : 31));
return result;
}
@@ -657,6 +660,9 @@ public class CodegenProperty implements Cloneable {
if (this.isEmail != other.isEmail) {
return false;
}
if (this.isFreeFormObject != other.isFreeFormObject) {
return false;
}
if (this.isBinary != other.isBinary) {
return false;
}
@@ -724,7 +730,7 @@ public class CodegenProperty implements Cloneable {
if (this.mostInnerItems != null) {
cp.mostInnerItems = this.mostInnerItems;
}
if(this.vendorExtensions != null){
if (this.vendorExtensions != null) {
cp.vendorExtensions = new HashMap<String, Object>(this.vendorExtensions);
}
return cp;
@@ -785,11 +791,12 @@ public class CodegenProperty implements Cloneable {
", isDateTime=" + isDateTime +
", isUuid=" + isUuid +
", isEmail=" + isEmail +
", isFreeFormObject=" + isFreeFormObject +
", isListContainer=" + isListContainer +
", isMapContainer=" + isMapContainer +
", isEnum=" + isEnum +
", isReadOnly=" + isReadOnly +
", isWriteOnly=" + isWriteOnly+
", isWriteOnly=" + isWriteOnly +
", isNullable=" + isNullable +
", _enum=" + _enum +
", allowableValues=" + allowableValues +

View File

@@ -17,11 +17,7 @@
package org.openapitools.codegen;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.*;
public class CodegenResponse {
public final List<CodegenProperty> headers = new ArrayList<CodegenProperty>();
@@ -30,7 +26,8 @@ public class CodegenResponse {
public List<Map<String, Object>> examples;
public String dataType, baseType, containerType;
public boolean hasHeaders;
public boolean isString, isNumeric, isInteger, isLong, isNumber, isFloat, isDouble, isByteArray, isBoolean, isDate, isDateTime, isUuid, isEmail;
public boolean isString, isNumeric, isInteger, isLong, isNumber, isFloat, isDouble, isByteArray, isBoolean, isDate,
isDateTime, isUuid, isEmail, isModel, isFreeFormObject;
public boolean isDefault;
public boolean simpleType;
public boolean primitiveType;
@@ -48,76 +45,90 @@ public class CodegenResponse {
@Override
public String toString() {
return String.format(Locale.ROOT, "%s(%s)", code, containerType);
return "CodegenResponse{" +
"headers=" + headers +
", code='" + code + '\'' +
", message='" + message + '\'' +
", hasMore=" + hasMore +
", examples=" + examples +
", dataType='" + dataType + '\'' +
", baseType='" + baseType + '\'' +
", containerType='" + containerType + '\'' +
", hasHeaders=" + hasHeaders +
", isString=" + isString +
", isNumeric=" + isNumeric +
", isInteger=" + isInteger +
", isLong=" + isLong +
", isNumber=" + isNumber +
", isFloat=" + isFloat +
", isDouble=" + isDouble +
", isByteArray=" + isByteArray +
", isBoolean=" + isBoolean +
", isDate=" + isDate +
", isDateTime=" + isDateTime +
", isUuid=" + isUuid +
", isEmail=" + isEmail +
", isFreeFormObject=" + isFreeFormObject +
", isModel=" + isModel +
", isDefault=" + isDefault +
", simpleType=" + simpleType +
", primitiveType=" + primitiveType +
", isMapContainer=" + isMapContainer +
", isListContainer=" + isListContainer +
", isBinary=" + isBinary +
", isFile=" + isFile +
", schema=" + schema +
", jsonSchema='" + jsonSchema + '\'' +
", vendorExtensions=" + vendorExtensions +
'}';
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
CodegenResponse that = (CodegenResponse) o;
if (!headers.equals(that.headers))
return false;
if (code != null ? !code.equals(that.code) : that.code != null)
return false;
if (message != null ? !message.equals(that.message) : that.message != null)
return false;
if (hasMore != that.hasMore)
return false;
if (examples != null ? !examples.equals(that.examples) : that.examples != null)
return false;
if (dataType != null ? !dataType.equals(that.dataType) : that.dataType != null)
return false;
if (baseType != null ? !baseType.equals(that.baseType) : that.baseType != null)
return false;
if (containerType != null ? !containerType.equals(that.containerType) : that.containerType != null)
return false;
if (isDefault != that.isDefault)
return false;
if (simpleType != that.simpleType)
return false;
if (primitiveType != that.primitiveType)
return false;
if (isMapContainer != that.isMapContainer)
return false;
if (isListContainer != that.isListContainer)
return false;
if (isBinary != that.isBinary)
return false;
if (isFile != that.isFile)
return false;
if (isNumeric != that.isNumeric)
return false;
if (schema != null ? !schema.equals(that.schema) : that.schema != null)
return false;
if (vendorExtensions != null ? !vendorExtensions.equals(that.vendorExtensions) : that.vendorExtensions != null)
return false;
return jsonSchema != null ? jsonSchema.equals(that.jsonSchema) : that.jsonSchema == null;
return hasMore == that.hasMore &&
hasHeaders == that.hasHeaders &&
isString == that.isString &&
isNumeric == that.isNumeric &&
isInteger == that.isInteger &&
isLong == that.isLong &&
isNumber == that.isNumber &&
isFloat == that.isFloat &&
isDouble == that.isDouble &&
isByteArray == that.isByteArray &&
isBoolean == that.isBoolean &&
isDate == that.isDate &&
isDateTime == that.isDateTime &&
isUuid == that.isUuid &&
isEmail == that.isEmail &&
isFreeFormObject == that.isFreeFormObject &&
isModel == that.isModel &&
isDefault == that.isDefault &&
simpleType == that.simpleType &&
primitiveType == that.primitiveType &&
isMapContainer == that.isMapContainer &&
isListContainer == that.isListContainer &&
isBinary == that.isBinary &&
isFile == that.isFile &&
Objects.equals(headers, that.headers) &&
Objects.equals(code, that.code) &&
Objects.equals(message, that.message) &&
Objects.equals(examples, that.examples) &&
Objects.equals(dataType, that.dataType) &&
Objects.equals(baseType, that.baseType) &&
Objects.equals(containerType, that.containerType) &&
Objects.equals(schema, that.schema) &&
Objects.equals(jsonSchema, that.jsonSchema) &&
Objects.equals(vendorExtensions, that.vendorExtensions);
}
@Override
public int hashCode() {
int result = headers.hashCode();
result = 31 * result + (code != null ? code.hashCode() : 0);
result = 31 * result + (message != null ? message.hashCode() : 0);
result = 31 * result + (hasMore ? 13:31);
result = 31 * result + (examples != null ? examples.hashCode() : 0);
result = 31 * result + (dataType != null ? dataType.hashCode() : 0);
result = 31 * result + (baseType != null ? baseType.hashCode() : 0);
result = 31 * result + (containerType != null ? containerType.hashCode() : 0);
result = 31 * result + (isDefault ? 13:31);
result = 31 * result + (isNumeric ? 13:31);
result = 31 * result + (simpleType ? 13:31);
result = 31 * result + (primitiveType ? 13:31);
result = 31 * result + (isMapContainer ? 13:31);
result = 31 * result + (isListContainer ? 13:31);
result = 31 * result + (isBinary ? 13:31);
result = 31 * result + (isFile ? 13:31);
result = 31 * result + (schema != null ? schema.hashCode() : 0);
result = 31 * result + (jsonSchema != null ? jsonSchema.hashCode() : 0);
result = 31 * result + (vendorExtensions != null ? vendorExtensions.hashCode() : 0);
return result;
return Objects.hash(headers, code, message, hasMore, examples, dataType, baseType, containerType, hasHeaders,
isString, isNumeric, isInteger, isLong, isNumber, isFloat, isDouble, isByteArray, isBoolean, isDate,
isDateTime, isUuid, isEmail, isFreeFormObject, isModel, isDefault, simpleType, primitiveType, isMapContainer,
isListContainer, isBinary, isFile, schema, jsonSchema, vendorExtensions);
}
}

View File

@@ -137,6 +137,9 @@ public class DefaultCodegen implements CodegenConfig {
// flag to indicate whether to use environment variable to post process file
protected boolean enablePostProcessFile = false;
// make openapi and schemas available to all methods
protected OpenAPI globalOpenAPI;
protected Map<String, Schema> globalSchemas;
public List<CliOption> cliOptions() {
return cliOptions;
@@ -383,6 +386,32 @@ public class DefaultCodegen implements CodegenConfig {
}
}
/**
* Set global OpenAPI based on OpenAPI object
*
* @param openAPI OpenAPI object
*/
public void setGlobalOpenAPI(OpenAPI openAPI) {
this.globalOpenAPI = openAPI;
}
/**
* Set global schema based on OpenAPI object
*
* @param openAPI OpenAPI object
*/
public void setGlobalSchemas(OpenAPI openAPI) {
if (openAPI != null && openAPI.getComponents() != null) {
this.globalSchemas = openAPI.getComponents().getSchemas();
}
if (this.globalSchemas == null) { // initalize with empty map if it's null
this.globalSchemas = new HashMap<String, Schema>();
}
}
// override with any special post-processing
@SuppressWarnings("static-method")
public Map<String, Object> postProcessOperations(Map<String, Object> objs) {
@@ -1152,6 +1181,8 @@ public class DefaultCodegen implements CodegenConfig {
codegenParameter.example = "38400000-8cf0-11bd-b23e-10b96e4ef00d";
} else if (Boolean.TRUE.equals(codegenParameter.isString)) {
codegenParameter.example = codegenParameter.paramName + "_example";
} else if (Boolean.TRUE.equals(codegenParameter.isFreeFormObject)) {
codegenParameter.example = "Object";
}
}
@@ -1375,6 +1406,8 @@ public class DefaultCodegen implements CodegenConfig {
return "UUID";
} else if (ModelUtils.isStringSchema(schema)) {
return "string";
} else if (ModelUtils.isFreeFormObject(schema)) {
return "object";
} else if (schema.getProperties() != null && !schema.getProperties().isEmpty()) { // having property implies it's a model
return "object";
} else if (StringUtils.isNotEmpty(schema.getType())) {
@@ -1685,7 +1718,8 @@ public class DefaultCodegen implements CodegenConfig {
return m;
}
private CodegenDiscriminator createDiscriminator(String schemaName, Schema schema, Map<String, Schema> allDefinitions) {
private CodegenDiscriminator createDiscriminator(String schemaName, Schema
schema, Map<String, Schema> allDefinitions) {
if (schema.getDiscriminator() == null) {
return null;
}
@@ -1717,7 +1751,8 @@ public class DefaultCodegen implements CodegenConfig {
addParentContainer(codegenModel, codegenModel.name, schema);
}
protected void addProperties(Map<String, Schema> properties, List<String> required, Schema schema, Map<String, Schema> allSchemas) {
protected void addProperties(Map<String, Schema> properties, List<String> required, Schema
schema, Map<String, Schema> allSchemas) {
if (schema instanceof ComposedSchema) {
ComposedSchema composedSchema = (ComposedSchema) schema;
if (composedSchema.getAllOf() == null) {
@@ -1756,6 +1791,7 @@ public class DefaultCodegen implements CodegenConfig {
return org.openapitools.codegen.utils.StringUtils.camelize(toVarName(name));
}
/**
* Convert OAS Property object to Codegen Property object
*
@@ -1769,6 +1805,10 @@ public class DefaultCodegen implements CodegenConfig {
return null;
}
LOGGER.debug("debugging fromProperty for " + name + " : " + p);
// unalias schema
p = ModelUtils.unaliasSchema(globalSchemas, p);
CodegenProperty property = CodegenModelFactory.newInstance(CodegenModelType.PROPERTY);
property.name = toVarName(name);
property.baseName = name;
@@ -1997,7 +2037,8 @@ public class DefaultCodegen implements CodegenConfig {
if (itemName == null) {
itemName = property.name;
}
CodegenProperty cp = fromProperty(itemName, ((ArraySchema) p).getItems());
Schema innerSchema = ModelUtils.unaliasSchema(globalSchemas, ((ArraySchema) p).getItems());
CodegenProperty cp = fromProperty(itemName, innerSchema);
updatePropertyForArray(property, cp);
} else if (ModelUtils.isMapSchema(p)) {
property.isContainer = true;
@@ -2008,8 +2049,12 @@ public class DefaultCodegen implements CodegenConfig {
property.maxItems = p.getMaxProperties();
// handle inner property
CodegenProperty cp = fromProperty("inner", ModelUtils.getAdditionalProperties(p));
Schema innerSchema = ModelUtils.unaliasSchema(globalSchemas, ModelUtils.getAdditionalProperties(p));
CodegenProperty cp = fromProperty("inner", innerSchema);
updatePropertyForMap(property, cp);
} else if (ModelUtils.isFreeFormObject(p)) {
property.isFreeFormObject = true;
property.baseType = getSchemaType(p);
} else { // model
// TODO revise the logic below
//if (StringUtils.isNotBlank(p.get$ref())) {
@@ -2212,7 +2257,8 @@ public class DefaultCodegen implements CodegenConfig {
* @param schemas a map of OAS models
* @return Codegen Operation object
*/
public CodegenOperation fromOperation(String path, String httpMethod, Operation operation, Map<String, Schema> schemas) {
public CodegenOperation fromOperation(String path, String httpMethod, Operation
operation, Map<String, Schema> schemas) {
return fromOperation(path, httpMethod, operation, schemas, null);
}
@@ -2298,10 +2344,8 @@ public class DefaultCodegen implements CodegenConfig {
op.responses.get(op.responses.size() - 1).hasMore = false;
if (methodResponse != null) {
Schema responseSchema = ModelUtils.getSchemaFromResponse(methodResponse);
if (openAPI != null && openAPI.getComponents() != null) { // has models/aliases defined
responseSchema = ModelUtils.unaliasSchema(openAPI.getComponents().getSchemas(), responseSchema);
}
Schema responseSchema = ModelUtils.unaliasSchema(globalSchemas, ModelUtils.getSchemaFromResponse(methodResponse));
if (responseSchema != null) {
CodegenProperty cm = fromProperty("response", responseSchema);
@@ -2321,7 +2365,13 @@ public class DefaultCodegen implements CodegenConfig {
}
// generate examples
op.examples = new ExampleGenerator(schemas, openAPI).generateFromResponseSchema(responseSchema, getProducesInfo(openAPI, operation));
String exampleStatusCode = "200";
for (String key : operation.getResponses().keySet()) {
if (operation.getResponses().get(key) == methodResponse && !key.equals("default")) {
exampleStatusCode = key;
}
}
op.examples = new ExampleGenerator(schemas, openAPI).generateFromResponseSchema(exampleStatusCode, responseSchema, getProducesInfo(openAPI, operation));
op.defaultResponse = toDefaultValue(responseSchema);
op.returnType = cm.dataType;
op.hasReference = schemas != null && schemas.containsKey(op.returnBaseType);
@@ -2549,7 +2599,12 @@ public class DefaultCodegen implements CodegenConfig {
} else {
r.code = responseCode;
}
final Schema responseSchema = ModelUtils.getSchemaFromResponse(response);
Schema responseSchema;
if (openAPI != null && openAPI.getComponents() != null) {
responseSchema = ModelUtils.unaliasSchema(openAPI.getComponents().getSchemas(), ModelUtils.getSchemaFromResponse(response));
} else { // no model/alias defined
responseSchema = ModelUtils.getSchemaFromResponse(response);
}
r.schema = responseSchema;
r.message = escapeText(response.getDescription());
// TODO need to revise and test examples in responses
@@ -2563,6 +2618,7 @@ public class DefaultCodegen implements CodegenConfig {
r.hasHeaders = !r.headers.isEmpty();
if (r.schema != null) {
Map<String, Schema> allSchemas = null;
CodegenProperty cp = fromProperty("response", responseSchema);
if (ModelUtils.isArraySchema(responseSchema)) {
@@ -2576,6 +2632,7 @@ public class DefaultCodegen implements CodegenConfig {
} else {
if (cp.complexType != null) {
r.baseType = cp.complexType;
r.isModel = true;
} else {
r.baseType = cp.baseType;
}
@@ -2616,6 +2673,8 @@ public class DefaultCodegen implements CodegenConfig {
r.isDate = true;
} else if (Boolean.TRUE.equals(cp.isDateTime)) {
r.isDateTime = true;
} else if (Boolean.TRUE.equals(cp.isFreeFormObject)) {
r.isFreeFormObject = true;
} else {
LOGGER.debug("Property type is not primitive: " + cp.dataType);
}
@@ -2651,7 +2710,8 @@ public class DefaultCodegen implements CodegenConfig {
* @param openAPI a OAS object representing the spec
* @return Codegen Response object
*/
public CodegenCallback fromCallback(String name, Callback callback, Map<String, Schema> schemas, OpenAPI openAPI) {
public CodegenCallback fromCallback(String name, Callback callback, Map<String, Schema> schemas, OpenAPI
openAPI) {
CodegenCallback c = new CodegenCallback();
c.name = name;
@@ -2985,6 +3045,12 @@ public class DefaultCodegen implements CodegenConfig {
LOGGER.warn("Unknown parameter type: " + parameter.getName());
}
// default to UNKNOWN_PARAMETER_NAME if paramName is null
if (codegenParameter.paramName == null) {
LOGGER.warn("Parameter name not defined properly. Default to UNKNOWN_PARAMETER_NAME");
codegenParameter.paramName = "UNKNOWN_PARAMETER_NAME";
}
// set the parameter excample value
// should be overridden by lang codegen
setParameterExampleValue(codegenParameter, parameter);
@@ -3189,6 +3255,7 @@ public class DefaultCodegen implements CodegenConfig {
String description = headers.getValue().getDescription();
// follow the $ref
Header header = ModelUtils.getReferencedHeader(openAPI, headers.getValue());
CodegenProperty cp = fromProperty(headers.getKey(), header.getSchema());
cp.setDescription(escapeText(description));
cp.setUnescapedDescription(description);
@@ -3221,7 +3288,8 @@ public class DefaultCodegen implements CodegenConfig {
* @param operations map of Codegen operations
*/
@SuppressWarnings("static-method")
public void addOperationToGroup(String tag, String resourcePath, Operation operation, CodegenOperation co, Map<String, List<CodegenOperation>> operations) {
public void addOperationToGroup(String tag, String resourcePath, Operation operation, CodegenOperation
co, Map<String, List<CodegenOperation>> operations) {
List<CodegenOperation> opList = operations.get(tag);
if (opList == null) {
opList = new ArrayList<CodegenOperation>();
@@ -3328,7 +3396,8 @@ public class DefaultCodegen implements CodegenConfig {
* @param properties model properties (schemas)
* @return model properties with direct reference to schemas
*/
private Map<String, Schema> unaliasPropertySchema(Map<String, Schema> allSchemas, Map<String, Schema> properties) {
private Map<String, Schema> unaliasPropertySchema
(Map<String, Schema> allSchemas, Map<String, Schema> properties) {
if (properties != null) {
for (String key : properties.keySet()) {
properties.put(key, ModelUtils.unaliasSchema(allSchemas, properties.get(key)));
@@ -3369,7 +3438,8 @@ public class DefaultCodegen implements CodegenConfig {
}
}
private void addVars(CodegenModel m, List<CodegenProperty> vars, Map<String, Schema> properties, Set<String> mandatory) {
private void addVars(CodegenModel
m, List<CodegenProperty> vars, Map<String, Schema> properties, Set<String> mandatory) {
// convert set to list so that we can access the next entry in the loop
List<Map.Entry<String, Schema>> propertyList = new ArrayList<Map.Entry<String, Schema>>(properties.entrySet());
final int totalCount = propertyList.size();
@@ -3882,6 +3952,8 @@ public class DefaultCodegen implements CodegenConfig {
} else if (Boolean.TRUE.equals(property.isDateTime)) {
parameter.isDateTime = true;
parameter.isPrimitiveType = true;
} else if (Boolean.TRUE.equals(property.isFreeFormObject)) {
parameter.isFreeFormObject = true;
} else {
LOGGER.debug("Property type is not primitive: " + property.dataType);
}
@@ -3955,7 +4027,8 @@ public class DefaultCodegen implements CodegenConfig {
}
}
private void updateEnumVarsWithExtensions(List<Map<String, Object>> enumVars, Map<String, Object> vendorExtensions) {
private void updateEnumVarsWithExtensions
(List<Map<String, Object>> enumVars, Map<String, Object> vendorExtensions) {
if (vendorExtensions != null && vendorExtensions.containsKey("x-enum-varnames")) {
List<String> alias = (List<String>) vendorExtensions.get("x-enum-varnames");
int size = Math.min(enumVars.size(), alias.size());
@@ -4266,7 +4339,8 @@ public class DefaultCodegen implements CodegenConfig {
return null;
}
public List<CodegenParameter> fromRequestBodyToFormParameters(RequestBody body, Map<String, Schema> schemas, Set<String> imports) {
public List<CodegenParameter> fromRequestBodyToFormParameters(RequestBody
body, Map<String, Schema> schemas, Set<String> imports) {
List<CodegenParameter> parameters = new ArrayList<CodegenParameter>();
LOGGER.debug("debugging fromRequestBodyToFormParameters= " + body);
Schema schema = ModelUtils.getSchemaFromRequestBody(body);
@@ -4422,7 +4496,8 @@ public class DefaultCodegen implements CodegenConfig {
return codegenParameter;
}
public CodegenParameter fromRequestBody(RequestBody body, Map<String, Schema> schemas, Set<String> imports, String bodyParameterName) {
public CodegenParameter fromRequestBody(RequestBody
body, Map<String, Schema> schemas, Set<String> imports, String bodyParameterName) {
if (body == null) {
LOGGER.error("body in fromRequestBody cannot be null!");
}
@@ -4729,7 +4804,7 @@ public class DefaultCodegen implements CodegenConfig {
/**
* Set the boolean value indicating the state of the option for post-processing file using envirionment variables.
*
* @param enablePostProcessFile true to enable post-processing file
* @param enablePostProcessFile true to enable post-processing file
*/
public void setEnablePostProcessFile(boolean enablePostProcessFile) {
this.enablePostProcessFile = enablePostProcessFile;

View File

@@ -38,7 +38,6 @@ import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.openapitools.codegen.ignore.CodegenIgnoreProcessor;
//import org.openapitools.codegen.languages.AbstractJavaCodegen;
import org.openapitools.codegen.utils.ImplementationVersion;
import org.openapitools.codegen.utils.ModelUtils;
import org.openapitools.codegen.utils.URLPathUtils;
@@ -170,7 +169,6 @@ public class DefaultGenerator extends AbstractGenerator implements Generator {
config.additionalProperties().put(CodegenConstants.EXCLUDE_TESTS, true);
}
if (System.getProperty("debugOpenAPI") != null) {
Json.prettyPrint(openAPI);
} else if (System.getProperty("debugSwagger") != null) {
@@ -182,6 +180,11 @@ public class DefaultGenerator extends AbstractGenerator implements Generator {
config.processOpts();
config.preprocessOpenAPI(openAPI);
// set OpenAPI and schemas to make these available to all methods
config.setGlobalOpenAPI(openAPI);
config.setGlobalSchemas(openAPI);
config.additionalProperties().put("generatorVersion", ImplementationVersion.read());
config.additionalProperties().put("generatedDate", ZonedDateTime.now().toString());
config.additionalProperties().put("generatedYear", String.valueOf(ZonedDateTime.now().getYear()));
@@ -425,6 +428,25 @@ public class DefaultGenerator extends AbstractGenerator implements Generator {
}
Schema schema = schemas.get(name);
// check to see if it's a "map" model
if (ModelUtils.isMapSchema(schema)) {
if (schema.getProperties() == null || schema.getProperties().isEmpty()) {
// schema without property, i.e. alias to map
LOGGER.info("Model " + name + " not generated since it's an alias to map (without property)");
continue;
}
}
// check to see if it's an "array" model
if (ModelUtils.isArraySchema(schema)) {
if (schema.getProperties() == null || schema.getProperties().isEmpty()) {
// schema without property, i.e. alias to array
LOGGER.info("Model " + name + " not generated since it's an alias to array (without property)");
continue;
}
}
Map<String, Schema> schemaMap = new HashMap<>();
schemaMap.put(name, schema);
Map<String, Object> models = processModels(config, schemaMap, schemas);
@@ -524,10 +546,31 @@ public class DefaultGenerator extends AbstractGenerator implements Generator {
operation.put("importPath", config.toApiImport(tag));
operation.put("classFilename", config.toApiFilename(tag));
if (allModels == null || allModels.isEmpty()) {
operation.put("hasModel", false);
} else {
operation.put("hasModel", true);
}
if (!config.vendorExtensions().isEmpty()) {
operation.put("vendorExtensions", config.vendorExtensions());
}
// process top-level x-group-parameters
if (config.vendorExtensions().containsKey("x-group-parameters")) {
Boolean isGroupParameters = Boolean.valueOf(config.vendorExtensions().get("x-group-parameters").toString());
Map<String, Object> objectMap = (Map<String, Object>) operation.get("operations");
@SuppressWarnings("unchecked")
List<CodegenOperation> operations = (List<CodegenOperation>) objectMap.get("operation");
for (CodegenOperation op : operations) {
op.httpMethod = op.httpMethod.toLowerCase(Locale.ROOT);
if (!op.vendorExtensions.containsKey("x-group-parameters")) {
op.vendorExtensions.put("x-group-parameters", Boolean.TRUE);
}
}
}
// Pass sortParamsByRequiredFlag through to the Mustache template...
boolean sortParamsByRequiredFlag = true;
if (this.config.additionalProperties().containsKey(CodegenConstants.SORT_PARAMS_BY_REQUIRED_FLAG)) {
@@ -1032,13 +1075,16 @@ public class DefaultGenerator extends AbstractGenerator implements Generator {
}
List<Map<String, String>> imports = new ArrayList<Map<String, String>>();
Set<String> mappingSet = new TreeSet<>();
for (String nextImport : allImports) {
Map<String, String> im = new LinkedHashMap<String, String>();
String mapping = config.importMapping().get(nextImport);
if (mapping == null) {
mapping = config.toModelImport(nextImport);
}
if (mapping != null) {
if (mapping != null && !mappingSet.contains(mapping)) { // ensure import (mapping) is unique
mappingSet.add(mapping);
im.put("import", mapping);
im.put("classname", nextImport);
if (!imports.contains(im)) { // avoid duplicates
@@ -1053,6 +1099,7 @@ public class DefaultGenerator extends AbstractGenerator implements Generator {
if (imports.size() > 0) {
operations.put("hasImport", true);
}
config.postProcessOperations(operations);
config.postProcessOperationsWithModels(operations, allModels);
if (objs.size() > 0) {

View File

@@ -42,6 +42,7 @@ public class ExampleGenerator {
private static final String NONE = "none";
private static final String URL = "url";
private static final String URI = "uri";
private static final String STATUS_CODE = "statusCode";
protected Map<String, Schema> examples;
private OpenAPI openAPI;
@@ -54,7 +55,20 @@ public class ExampleGenerator {
this.random = new Random("ExampleGenerator".hashCode());
}
public List<Map<String, String>> generateFromResponseSchema(Schema responseSchema, Set<String> producesInfo) {
public List<Map<String, String>> generateFromResponseSchema(String statusCode, Schema responseSchema, Set<String> producesInfo) {
List<Map<String, String>> examples = generateFromResponseSchema(responseSchema, producesInfo);
if (examples == null) {
return null;
}
for (Map<String, String> example : examples) {
example.put(STATUS_CODE, statusCode);
}
return examples;
}
private List<Map<String, String>> generateFromResponseSchema(Schema responseSchema, Set<String> producesInfo) {
if (responseSchema.getExample() == null && StringUtils.isEmpty(responseSchema.get$ref()) && !ModelUtils.isArraySchema(responseSchema)) {
// no example provided
return null;

View File

@@ -18,6 +18,7 @@
package org.openapitools.codegen.languages;
import java.util.*;
import com.google.common.base.Strings;
import org.apache.commons.lang3.StringUtils;
import org.openapitools.codegen.CodegenConfig;
@@ -35,8 +36,6 @@ import io.swagger.v3.oas.models.responses.ApiResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public abstract class AbstractApexCodegen extends DefaultCodegen implements CodegenConfig {
private static final Logger LOGGER = LoggerFactory.getLogger(AbstractApexCodegen.class);
@@ -325,7 +324,7 @@ public abstract class AbstractApexCodegen extends DefaultCodegen implements Code
if (example.isEmpty()) {
example = "VGhlIHF1aWNrIGJyb3duIGZveCBqdW1wZWQgb3ZlciB0aGUgbGF6eSBkb2cu";
}
((ByteArraySchema) p).setExample(example);
p.setExample(example);
example = "EncodingUtil.base64Decode('" + example + "')";
} else if (ModelUtils.isDateSchema(p)) {
if (example.matches("^\\d{4}(-\\d{2}){2}")) {

View File

@@ -160,21 +160,21 @@ public abstract class AbstractCSharpCodegen extends DefaultCodegen implements Co
typeMapping = new HashMap<String, String>();
typeMapping.put("string", "string");
typeMapping.put("binary", "byte[]");
typeMapping.put("bytearray", "byte[]");
typeMapping.put("ByteArray", "byte[]");
typeMapping.put("boolean", "bool?");
typeMapping.put("integer", "int?");
typeMapping.put("float", "float?");
typeMapping.put("long", "long?");
typeMapping.put("double", "double?");
typeMapping.put("number", "decimal?");
typeMapping.put("datetime", "DateTime?");
typeMapping.put("DateTime", "DateTime?");
typeMapping.put("date", "DateTime?");
typeMapping.put("file", "System.IO.Stream");
typeMapping.put("array", "List");
typeMapping.put("list", "List");
typeMapping.put("map", "Dictionary");
typeMapping.put("object", "Object");
typeMapping.put("uuid", "Guid?");
typeMapping.put("UUID", "Guid?");
}
public void setReturnICollection(boolean returnICollection) {
@@ -216,6 +216,7 @@ public abstract class AbstractCSharpCodegen extends DefaultCodegen implements Co
if (StringUtils.isEmpty(System.getenv("CSHARP_POST_PROCESS_FILE"))) {
LOGGER.info("Environment variable CSHARP_POST_PROCESS_FILE not defined so the C# code may not be properly formatted by uncrustify (0.66 or later) or other code formatter. To define it, try `export CSHARP_POST_PROCESS_FILE=\"/usr/local/bin/uncrustify --no-backup\" && export UNCRUSTIFY_CONFIG=/path/to/uncrustify-rules.cfg` (Linux/Mac). Note: replace /path/to with the location of uncrustify-rules.cfg");
LOGGER.info("NOTE: To enable file post-processing, 'enablePostProcessFile' must be set to `true` (--enable-post-process-file for CLI).");
}
// {{packageVersion}}
@@ -766,20 +767,19 @@ public abstract class AbstractCSharpCodegen extends DefaultCodegen implements Co
String type;
if (openAPIType == null) {
openAPIType = ""; // set swagger type to empty string if null
LOGGER.error("OpenAPI Type for {} is null. Default to UNKNOWN_OPENAPI_TYPE instead.", p.getName());
openAPIType = "UNKNOWN_OPENAPI_TYPE";
}
// NOTE: typeMapping here supports things like string/String, long/Long, datetime/DateTime as lowercase keys.
// Should we require explicit casing here (values are not insensitive).
// TODO avoid using toLowerCase as typeMapping should be case-sensitive
if (typeMapping.containsKey(openAPIType.toLowerCase(Locale.ROOT))) {
type = typeMapping.get(openAPIType.toLowerCase(Locale.ROOT));
if (typeMapping.containsKey(openAPIType)) {
type = typeMapping.get(openAPIType);
if (languageSpecificPrimitives.contains(type)) {
return type;
}
} else {
type = openAPIType;
}
return toModelName(type);
}

View File

@@ -19,6 +19,8 @@ package org.openapitools.codegen.languages;
import io.swagger.v3.oas.models.media.Schema;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang3.StringUtils;
import com.google.common.collect.ImmutableMap;
import com.samskivert.mustache.Mustache;
import org.openapitools.codegen.CodegenConfig;
@@ -28,6 +30,7 @@ import org.openapitools.codegen.mustache.IndentedLambda;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File;
import java.util.Arrays;
import java.util.Map;
@@ -226,8 +229,8 @@ abstract public class AbstractCppCodegen extends DefaultCodegen implements Codeg
nameInCamelCase = sanitizeName(nameInCamelCase);
}
if (isReservedWord(nameInCamelCase) || nameInCamelCase.matches("^\\d.*")) {
nameInCamelCase = escapeReservedWord(nameInCamelCase);
}
nameInCamelCase = escapeReservedWord(nameInCamelCase);
}
property.nameInCamelCase = nameInCamelCase;
return property;
}
@@ -249,6 +252,12 @@ abstract public class AbstractCppCodegen extends DefaultCodegen implements Codeg
public void processOpts() {
super.processOpts();
if (StringUtils.isEmpty(System.getenv("CPP_POST_PROCESS_FILE"))) {
LOGGER.info("Environment variable CPP_POST_PROCESS_FILE not defined so the C++ code may not be properly formatted. To define it, try 'export CPP_POST_PROCESS_FILE=\"/usr/local/bin/clang-format -i\"' (Linux/Mac)");
LOGGER.info("NOTE: To enable file post-processing, 'enablePostProcessFile' must be set to `true` (--enable-post-process-file for CLI).");
}
addMustacheLambdas(additionalProperties);
}
@@ -265,4 +274,31 @@ abstract public class AbstractCppCodegen extends DefaultCodegen implements Codeg
objs.put("lambda", lambdas);
}
}
@Override
public void postProcessFile(File file, String fileType) {
if (file == null) {
return;
}
String cppPostProcessFile = System.getenv("CPP_POST_PROCESS_FILE");
if (StringUtils.isEmpty(cppPostProcessFile)) {
return; // skip if CPP_POST_PROCESS_FILE env variable is not defined
}
// only process files with cpp extension
if ("cpp".equals(FilenameUtils.getExtension(file.toString())) || "h".equals(FilenameUtils.getExtension(file.toString()))) {
String command = cppPostProcessFile + " " + file.toString();
try {
Process p = Runtime.getRuntime().exec(command);
p.waitFor();
int exitValue = p.exitValue();
if (exitValue != 0) {
LOGGER.error("Error running the command ({}). Exit value: {}", command, exitValue);
} else {
LOGGER.info("Successfully executed: " + command);
}
} catch (Exception e) {
LOGGER.error("Error running the command ({}). Exception: {}", command, e.getMessage());
}
}
}
}

View File

@@ -121,6 +121,7 @@ public abstract class AbstractGoCodegen extends DefaultCodegen implements Codege
if (StringUtils.isEmpty(System.getenv("GO_POST_PROCESS_FILE"))) {
LOGGER.info("Environment variable GO_POST_PROCESS_FILE not defined so Go code may not be properly formatted. To define it, try `export GO_POST_PROCESS_FILE=\"/usr/local/bin/gofmt -w\"` (Linux/Mac)");
LOGGER.info("NOTE: To enable file post-processing, 'enablePostProcessFile' must be set to `true` (--enable-post-process-file for CLI).");
}
}

View File

@@ -215,6 +215,7 @@ public abstract class AbstractJavaCodegen extends DefaultCodegen implements Code
if (StringUtils.isEmpty(System.getenv("JAVA_POST_PROCESS_FILE"))) {
LOGGER.info("Environment variable JAVA_POST_PROCESS_FILE not defined so the Java code may not be properly formatted. To define it, try 'export JAVA_POST_PROCESS_FILE=\"/usr/local/bin/clang-format -i\"' (Linux/Mac)");
LOGGER.info("NOTE: To enable file post-processing, 'enablePostProcessFile' must be set to `true` (--enable-post-process-file for CLI).");
}
if (additionalProperties.containsKey(SUPPORT_JAVA6)) {
@@ -1397,7 +1398,7 @@ public abstract class AbstractJavaCodegen extends DefaultCodegen implements Code
return; // skip if JAVA_POST_PROCESS_FILE env variable is not defined
}
// only process files with hs extension
// only process files with java extension
if ("java".equals(FilenameUtils.getExtension(file.toString()))) {
String command = javaPostProcessFile + " " + file.toString();
try {

View File

@@ -19,6 +19,7 @@ package org.openapitools.codegen.languages;
import io.swagger.v3.oas.models.media.ArraySchema;
import io.swagger.v3.oas.models.media.Schema;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang3.StringUtils;
import org.openapitools.codegen.CliOption;
import org.openapitools.codegen.CodegenConfig;
@@ -44,6 +45,7 @@ public abstract class AbstractKotlinCodegen extends DefaultCodegen implements Co
protected String apiDocPath = "docs/";
protected String modelDocPath = "docs/";
protected boolean parcelizeModels = false;
protected CodegenConstants.ENUM_PROPERTY_NAMING_TYPE enumPropertyNaming = CodegenConstants.ENUM_PROPERTY_NAMING_TYPE.camelCase;
@@ -198,6 +200,7 @@ public abstract class AbstractKotlinCodegen extends DefaultCodegen implements Co
CliOption enumPropertyNamingOpt = new CliOption(CodegenConstants.ENUM_PROPERTY_NAMING, CodegenConstants.ENUM_PROPERTY_NAMING_DESC);
cliOptions.add(enumPropertyNamingOpt.defaultValue(enumPropertyNaming.name()));
cliOptions.add(new CliOption(CodegenConstants.PARCELIZE_MODELS, CodegenConstants.PARCELIZE_MODELS_DESC));
}
@Override
@@ -308,6 +311,11 @@ public abstract class AbstractKotlinCodegen extends DefaultCodegen implements Co
public void processOpts() {
super.processOpts();
if (StringUtils.isEmpty(System.getenv("KOTLIN_POST_PROCESS_FILE"))) {
LOGGER.info("Environment variable KOTLIN_POST_PROCESS_FILE not defined so the Kotlin code may not be properly formatted. To define it, try 'export KOTLIN_POST_PROCESS_FILE=\"/usr/local/bin/ktlint -F\"' (Linux/Mac)");
LOGGER.info("NOTE: To enable file post-processing, 'enablePostProcessFile' must be set to `true` (--enable-post-process-file for CLI).");
}
if (additionalProperties.containsKey(CodegenConstants.ENUM_PROPERTY_NAMING)) {
setEnumPropertyNaming((String) additionalProperties.get(CodegenConstants.ENUM_PROPERTY_NAMING));
}
@@ -350,6 +358,20 @@ public abstract class AbstractKotlinCodegen extends DefaultCodegen implements Co
LOGGER.warn(CodegenConstants.INVOKER_PACKAGE + " with " + this.getName() + " generator is ignored. Use " + CodegenConstants.PACKAGE_NAME + ".");
}
if (additionalProperties.containsKey(CodegenConstants.PARCELIZE_MODELS)) {
this.setParcelizeModels(Boolean.valueOf((String)additionalProperties.get(CodegenConstants.PARCELIZE_MODELS)));
LOGGER.info(CodegenConstants.PARCELIZE_MODELS + " depends on the android framework and " +
"experimental parcelize feature. Make sure your build applies the android plugin:\n" +
"apply plugin: 'com.android.library' OR apply plugin: 'com.android.application'.\n" +
"and enables the experimental features:\n" +
"androidExtensions {\n" +
" experimental = true\n" +
"}"
);
} else {
additionalProperties.put(CodegenConstants.PARCELIZE_MODELS, parcelizeModels);
}
additionalProperties.put(CodegenConstants.API_PACKAGE, apiPackage());
additionalProperties.put(CodegenConstants.MODEL_PACKAGE, modelPackage());
@@ -377,6 +399,14 @@ public abstract class AbstractKotlinCodegen extends DefaultCodegen implements Co
this.sourceFolder = sourceFolder;
}
public Boolean getParcelizeModels() {
return parcelizeModels;
}
public void setParcelizeModels(Boolean parcelizeModels) {
this.parcelizeModels = parcelizeModels;
}
/**
* Return the sanitized variable name for enum
*
@@ -684,4 +714,33 @@ public abstract class AbstractKotlinCodegen extends DefaultCodegen implements Co
}
return startsWithTwoUppercaseLetters;
}
@Override
public void postProcessFile(File file, String fileType) {
if (file == null) {
return;
}
String kotlinPostProcessFile = System.getenv("KOTLIN_POST_PROCESS_FILE");
if (StringUtils.isEmpty(kotlinPostProcessFile)) {
return; // skip if KOTLIN_POST_PROCESS_FILE env variable is not defined
}
// only process files with kt extension
if ("kt".equals(FilenameUtils.getExtension(file.toString()))) {
String command = kotlinPostProcessFile + " " + file.toString();
try {
Process p = Runtime.getRuntime().exec(command);
p.waitFor();
int exitValue = p.exitValue();
if (exitValue != 0) {
LOGGER.error("Error running the command ({}). Exit value: {}", command, exitValue);
} else {
LOGGER.info("Successfully executed: " + command);
}
} catch (Exception e) {
LOGGER.error("Error running the command ({}). Exception: {}", command, e.getMessage());
}
}
}
}

View File

@@ -18,6 +18,7 @@ package org.openapitools.codegen.languages;
import io.swagger.v3.oas.models.media.ArraySchema;
import io.swagger.v3.oas.models.media.Schema;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang3.StringUtils;
import org.openapitools.codegen.CliOption;
import org.openapitools.codegen.CodegenConfig;
@@ -40,12 +41,6 @@ import java.util.Locale;
import java.util.Map;
import java.util.regex.Matcher;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public abstract class AbstractPhpCodegen extends DefaultCodegen implements CodegenConfig {
private static final Logger LOGGER = LoggerFactory.getLogger(AbstractPhpCodegen.class);
@@ -161,6 +156,11 @@ public abstract class AbstractPhpCodegen extends DefaultCodegen implements Codeg
public void processOpts() {
super.processOpts();
if (StringUtils.isEmpty(System.getenv("PHP_POST_PROCESS_FILE"))) {
LOGGER.info("Environment variable PHP_POST_PROCESS_FILE not defined so the PHP code may not be properly formatted. To define it, try 'export PHP_POST_PROCESS_FILE=\"/usr/local/bin/prettier --write\"' (Linux/Mac)");
LOGGER.info("NOTE: To enable file post-processing, 'enablePostProcessFile' must be set to `true` (--enable-post-process-file for CLI).");
}
if (additionalProperties.containsKey(PACKAGE_NAME)) {
this.setPackageName((String) additionalProperties.get(PACKAGE_NAME));
} else {
@@ -773,4 +773,31 @@ public abstract class AbstractPhpCodegen extends DefaultCodegen implements Codeg
final int lastBackslashIndex = phpClassName.lastIndexOf('\\');
return phpClassName.substring(lastBackslashIndex + 1);
}
@Override
public void postProcessFile(File file, String fileType) {
if (file == null) {
return;
}
String phpPostProcessFile = System.getenv("PHP_POST_PROCESS_FILE");
if (StringUtils.isEmpty(phpPostProcessFile)) {
return; // skip if PHP_POST_PROCESS_FILE env variable is not defined
}
// only process files with php extension
if ("php".equals(FilenameUtils.getExtension(file.toString()))) {
String command = phpPostProcessFile + " " + file.toString();
try {
Process p = Runtime.getRuntime().exec(command);
p.waitFor();
int exitValue = p.exitValue();
if (exitValue != 0) {
LOGGER.error("Error running the command ({}). Exit value: {}", command, exitValue);
} else {
LOGGER.info("Successfully executed: " + command);
}
} catch (Exception e) {
LOGGER.error("Error running the command ({}). Exception: {}", command, e.getMessage());
}
}
}
}

View File

@@ -146,6 +146,10 @@ abstract class AbstractRubyCodegen extends DefaultCodegen implements CodegenConf
return name;
}
public String toRegularExpression(String pattern) {
return addRegularExpressionDelimiter(pattern);
}
@Override
public String toParamName(String name) {
// should be the same as variable name

View File

@@ -116,6 +116,7 @@ public abstract class AbstractScalaCodegen extends DefaultCodegen {
if (StringUtils.isEmpty(System.getenv("SCALA_POST_PROCESS_FILE"))) {
LOGGER.info("Environment variable SCALA_POST_PROCESS_FILE not defined so the Scala code may not be properly formatted. To define it, try 'export SCALA_POST_PROCESS_FILE=/usr/local/bin/scalafmt' (Linux/Mac)");
LOGGER.info("NOTE: To enable file post-processing, 'enablePostProcessFile' must be set to `true` (--enable-post-process-file for CLI).");
}
if (additionalProperties.containsKey(CodegenConstants.SOURCE_FOLDER)) {

View File

@@ -26,6 +26,7 @@ import io.swagger.v3.oas.models.info.*;
import io.swagger.v3.oas.models.OpenAPI;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File;
import java.util.*;
@@ -224,7 +225,7 @@ public class ApexClientCodegen extends AbstractApexCodegen {
);
} else if (ModelUtils.isBooleanSchema(p)) {
// true => "true", false => "false", null => "null"
out = String.valueOf(((BooleanSchema) p).getDefault());
out = String.valueOf(p.getDefault());
} else if (ModelUtils.isLongSchema(p)) {
Long def = (Long) p.getDefault();
out = def == null ? out : def.toString() + "L";

View File

@@ -251,4 +251,9 @@ public class AspNetCoreServerCodegen extends AbstractCSharpCodegen {
// To avoid unexpected behaviors when options are passed programmatically such as { "useCollection": "" }
return super.processCompiler(compiler).emptyStringIsFalse(true);
}
@Override
public String toRegularExpression(String pattern) {
return escapeText(pattern);
}
}

View File

@@ -0,0 +1,630 @@
/*
* Copyright 2018 OpenAPI-Generator Contributors (https://openapi-generator.tech)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.openapitools.codegen.languages;
import io.swagger.v3.oas.models.media.ArraySchema;
import io.swagger.v3.oas.models.media.Schema;
import org.apache.commons.lang3.StringUtils;
import org.openapitools.codegen.*;
import org.openapitools.codegen.utils.ModelUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.io.FilenameUtils;
import java.io.File;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
public class CLibcurlClientCodegen extends DefaultCodegen implements CodegenConfig {
private static final Logger LOGGER = LoggerFactory.getLogger(CLibcurlClientCodegen.class);
protected String moduleName;
protected String specFolder = "spec";
protected String libFolder = "lib";
protected String apiDocPath = "docs/";
protected String modelDocPath = "docs/";
protected static int emptyMethodNameCounter = 0;
public CLibcurlClientCodegen() {
super();
modelPackage = "models";
apiPackage = "api";
outputFolder = "generated-code" + File.separator + "C-libcurl";
modelTemplateFiles.put("model-header.mustache", ".h");
modelTemplateFiles.put("model-body.mustache", ".c");
apiTemplateFiles.put("api-header.mustache", ".h");
apiTemplateFiles.put("api-body.mustache", ".c");
//modelDocTemplateFiles.put("model_doc.mustache", ".md");
//apiDocTemplateFiles.put("api_doc.mustache", ".md");
embeddedTemplateDir = templateDir = "C-libcurl";
// TODO add auto-generated test files
//modelTestTemplateFiles.put("model_test.mustache", ".c");
//apiTestTemplateFiles.put("api_test.mustache", ".c");
// default HIDE_GENERATION_TIMESTAMP to true
hideGenerationTimestamp = Boolean.TRUE;
setReservedWordsLowerCase(
Arrays.asList(
// local variable names used in API methods (endpoints)
// c reserved keywords
// ref: https://en.cppreference.com/w/c/keyword
"auto",
"break",
"case",
"char",
"const",
"continue",
"default",
"do",
"double",
"else",
"enum",
"extern",
"float",
"for",
"goto",
"if",
"inline",
"int",
"long",
"register",
"restrict",
"return",
"short",
"signed",
"sizeof",
"static",
"struct",
"switch",
"typedef",
"union",
"unsigned",
"void",
"volatile",
"while",
"_Alignas",
"_Alignof",
"_Atomic",
"_Bool",
"_Complex",
"_Generic",
"_Imaginary",
"_Noreturn",
"_Static_assert",
"_Thread_local")
);
instantiationTypes.clear();
typeMapping.clear();
importMapping.clear();
languageSpecificPrimitives.clear();
// primitives in C lang
languageSpecificPrimitives.add("int");
languageSpecificPrimitives.add("short");
languageSpecificPrimitives.add("int");
languageSpecificPrimitives.add("long");
languageSpecificPrimitives.add("float");
languageSpecificPrimitives.add("double");
languageSpecificPrimitives.add("char");
languageSpecificPrimitives.add("FILE");
languageSpecificPrimitives.add("Object");
languageSpecificPrimitives.add("list_t*");
typeMapping.put("string", "char");
typeMapping.put("char", "char");
typeMapping.put("integer", "int");
typeMapping.put("long", "long");
typeMapping.put("float", "double");
typeMapping.put("double", "float");
typeMapping.put("number", "float");
typeMapping.put("date", "char");
typeMapping.put("DateTime", "char");
typeMapping.put("boolean", "int");
typeMapping.put("file", "FILE");
typeMapping.put("binary", "char");
typeMapping.put("ByteArray", "char");
typeMapping.put("UUID", "char");
typeMapping.put("array", "list");
typeMapping.put("map", "list_t*");
typeMapping.put("date-time", "char");
// remove modelPackage and apiPackage added by default
Iterator<CliOption> itr = cliOptions.iterator();
while (itr.hasNext()) {
CliOption opt = itr.next();
if (CodegenConstants.MODEL_PACKAGE.equals(opt.getOpt()) ||
CodegenConstants.API_PACKAGE.equals(opt.getOpt())) {
itr.remove();
}
}
cliOptions.add(new CliOption(CodegenConstants.HIDE_GENERATION_TIMESTAMP, CodegenConstants.HIDE_GENERATION_TIMESTAMP_DESC).
defaultValue(Boolean.TRUE.toString()));
}
@Override
public void processOpts() {
super.processOpts();
if (StringUtils.isEmpty(System.getenv("C_POST_PROCESS_FILE"))) {
LOGGER.info("Environment variable C_POST_PROCESS_FILE not defined so the C code may not be properly formatted by uncrustify (0.66 or later) or other code formatter. To define it, try `export C_POST_PROCESS_FILE=\"/usr/local/bin/uncrustify --no-backup\" && export UNCRUSTIFY_CONFIG=/path/to/uncrustify-rules.cfg` (Linux/Mac). Note: replace /path/to with the location of uncrustify-rules.cfg");
}
// make api and model doc path available in mustache template
additionalProperties.put("apiDocPath", apiDocPath);
additionalProperties.put("modelDocPath", modelDocPath);
// use constant model/api package (folder path)
setModelPackage("models");
setApiPackage("api");
// root folder
supportingFiles.add(new SupportingFile("CMakeLists.txt.mustache", "", "CMakeLists.txt"));
supportingFiles.add(new SupportingFile("libcurl.licence.mustache", "", "libcurl.licence"));
supportingFiles.add(new SupportingFile("uncrustify-rules.cfg.mustache", "", "uncrustify-rules.cfg"));
supportingFiles.add(new SupportingFile("README.md.mustache", "", "README.md"));
// src folder
supportingFiles.add(new SupportingFile("apiClient.c.mustache", "src", "apiClient.c"));
supportingFiles.add(new SupportingFile("apiKey.c.mustache", "src", "apiKey.c"));
supportingFiles.add(new SupportingFile("list.c.mustache", "src", "list.c"));
// include folder
supportingFiles.add(new SupportingFile("apiClient.h.mustache", "include", "apiClient.h"));
supportingFiles.add(new SupportingFile("keyValuePair.h.mustache", "include", "keyValuePair.h"));
supportingFiles.add(new SupportingFile("list.h.mustache", "include", "list.h"));
// external folder
supportingFiles.add(new SupportingFile("cJSON.licence.mustache", "external", "cJSON.licence"));
supportingFiles.add(new SupportingFile("cJSON.c.mustache", "external" + File.separator + "src", "cJSON.c"));
supportingFiles.add(new SupportingFile("cJSON.h.mustache", "external" + File.separator + "include", "cJSON.h"));
}
@Override
public CodegenType getTag() {
return CodegenType.CLIENT;
}
@Override
public String getName() {
return "c";
}
@Override
public String getHelp() {
return "Generates a C (libcurl) client library (beta).";
}
@Override
public String escapeReservedWord(String name) {
if (this.reservedWordsMappings().containsKey(name)) {
return this.reservedWordsMappings().get(name);
}
return "_" + name;
}
@Override
public String apiFileFolder() {
return outputFolder + File.separator + "api";
}
@Override
public String modelFileFolder() {
return outputFolder + File.separator + "model";
}
@Override
public String apiTestFileFolder() {
return outputFolder + File.separator + "unit-test";
}
@Override
public String modelTestFileFolder() {
return outputFolder + File.separator + "unit-test";
}
@Override
public String apiDocFileFolder() {
return (outputFolder + "/" + apiDocPath).replace('/', File.separatorChar);
}
@Override
public String modelDocFileFolder() {
return (outputFolder + "/" + modelDocPath).replace('/', File.separatorChar);
}
@Override
public String getTypeDeclaration(Schema schema) {
/* comment out below as we'll do it in the template instead
if (ModelUtils.isArraySchema(schema)) {
Schema inner = ((ArraySchema) schema).getItems();
return getSchemaType(schema) + "<" + getTypeDeclaration(inner) + ">";
} else if (ModelUtils.isMapSchema(schema)) {
Schema inner = (Schema) schema.getAdditionalProperties();
return getSchemaType(schema) + "<String, " + getTypeDeclaration(inner) + ">";
}
*/
return super.getTypeDeclaration(schema);
}
@Override
public String toDefaultValue(Schema p) {
if (ModelUtils.isIntegerSchema(p) || ModelUtils.isNumberSchema(p) || ModelUtils.isBooleanSchema(p)) {
if (p.getDefault() != null) {
return p.getDefault().toString();
}
} else if (ModelUtils.isStringSchema(p)) {
if (p.getDefault() != null) {
return "'" + escapeText((String) p.getDefault()) + "'";
}
}
return null;
}
@Override
public String getSchemaType(Schema schema) {
String openAPIType = super.getSchemaType(schema);
String type = null;
if (typeMapping.containsKey(openAPIType)) {
type = typeMapping.get(openAPIType);
if (languageSpecificPrimitives.contains(type)) {
return type;
}
} else {
type = openAPIType;
}
if (type == null) {
return null;
}
return toModelName(type);
}
@Override
public String toVarName(String name) {
// sanitize name
name = sanitizeName(name); // FIXME: a parameter should not be assigned. Also declare the methods parameters as 'final'.
// if it's all uppper case, convert to lower case
if (name.matches("^[A-Z_]*$")) {
name = name.toLowerCase(Locale.ROOT);
}
name = underscore(name);
// for reserved word or word starting with number, append _
if (isReservedWord(name) || name.matches("^\\d.*")) {
name = escapeReservedWord(name);
}
return name;
}
@Override
public String toParamName(String name) {
// should be the same as variable name
name = name.replaceAll("-","_");
return name;
}
@Override
public String toModelName(String name) {
name = sanitizeName(name); // FIXME: a parameter should not be assigned. Also declare the methods parameters as 'final'.
if (!StringUtils.isEmpty(modelNamePrefix)) {
name = modelNamePrefix + "_" + name;
}
if (!StringUtils.isEmpty(modelNameSuffix)) {
name = name + "_" + modelNameSuffix;
}
// model name cannot use reserved keyword, e.g. return
if (isReservedWord(name)) {
String modelName = camelize("Model" + name);
LOGGER.warn(name + " (reserved word) cannot be used as model name. Renamed to " + modelName);
return modelName;
}
// model name starts with number
if (name.matches("^\\d.*")) {
LOGGER.warn(name + " (model name starts with number) cannot be used as model name. Renamed to " + camelize("model_" + name));
name = "model_" + name; // e.g. 200Response => Model200Response (after camelize)
}
// camelize the model name
// phone_number => PhoneNumber
return underscore(name);
}
@Override
public String toModelFilename(String name) {
return underscore(toModelName(name));
}
@Override
public String toModelDocFilename(String name) {
return toModelName(name);
}
@Override
public String toApiFilename(String name) {
// replace - with _ e.g. created-at => created_at
name = name.replaceAll("-", "_"); // FIXME: a parameter should not be assigned. Also declare the methods parameters as 'final'.
// e.g. PhoneNumberApi.rb => phone_number_api.rb
return camelize(name) + "API";
}
@Override
public String toApiDocFilename(String name) {
return toApiName(name);
}
@Override
public String toApiTestFilename(String name) {
return ("test_" + toApiFilename(name)).replaceAll("_", "-");
}
@Override
public String toModelTestFilename(String name) {
return ("test_" + toModelFilename(name)).replaceAll("_", "-");
}
@Override
public String toApiName(String name) {
if (name.length() == 0) {
return "DefaultApi";
}
// e.g. phone_number_api => PhoneNumberApi
return camelize(name) + "API";
}
@Override
public String toEnumValue(String value, String datatype) {
if ("Integer".equals(datatype) || "Float".equals(datatype)) {
return value;
} else {
if (value.matches("\\d.*")) { // starts with number
return "N" + escapeText(value);
} else {
return escapeText(value);
}
}
}
@Override
public String toEnumVarName(String name, String datatype) {
if (name.length() == 0) {
return "EMPTY";
}
// number
if ("Integer".equals(datatype) || "Float".equals(datatype)) {
String varName = name;
varName = varName.replaceAll("-", "MINUS_");
varName = varName.replaceAll("\\+", "PLUS_");
varName = varName.replaceAll("\\.", "_DOT_");
return varName;
}
// string
String enumName = sanitizeName(camelize(name).toUpperCase(Locale.ROOT));
enumName = enumName.replaceFirst("^_", "");
enumName = enumName.replaceFirst("_$", "");
if (enumName.matches("\\d.*")) { // starts with number
return "N" + enumName;
} else {
return enumName;
}
}
@Override
public String toEnumName(CodegenProperty property) {
String enumName = camelize(toModelName(property.name)).toUpperCase(Locale.ROOT);
enumName = enumName.replaceFirst("^_", "");
enumName = enumName.replaceFirst("_$", "");
if (enumName.matches("\\d.*")) { // starts with number
return "N" + enumName;
} else {
return enumName;
}
}
@Override
public Map<String, Object> postProcessModels(Map<String, Object> objs) {
// process enum in models
return postProcessModelsEnum(objs);
}
@Override
public String toOperationId(String operationId) {
// rename to empty_method_name_1 (e.g.) if method name is empty
if (StringUtils.isEmpty(operationId)) {
operationId = camelize("empty_method_name_" + emptyMethodNameCounter++);
LOGGER.warn("Empty method name (operationId) found. Renamed to " + operationId);
return operationId;
}
// method name cannot use reserved keyword, e.g. return
if (isReservedWord(operationId)) {
String newOperationId = camelize(sanitizeName("call_" + operationId), true);
LOGGER.warn(operationId + " (reserved word) cannot be used as method name. Renamed to " + newOperationId);
return newOperationId;
}
// operationId starts with a number
if (operationId.matches("^\\d.*")) {
String newOperationId = camelize(sanitizeName("call_" + operationId), true);
LOGGER.warn(operationId + " (starting with a number) cannot be used as method name. Renamed to " + newOperationId);
return newOperationId;
}
return camelize(sanitizeName(operationId), true);
}
@Override
public String toApiImport(String name) {
return apiPackage() + "/" + toApiFilename(name);
}
@Override
public String toModelImport(String name) {
return "#include \"" + name + ".h\"";
}
@Override
public void setParameterExampleValue(CodegenParameter p) {
String example;
if (p.defaultValue == null) {
example = p.example;
} else {
p.example = p.defaultValue;
return;
}
String type = p.baseType;
if (type == null) {
type = p.dataType;
}
if ("String".equals(type)) {
if (example == null) {
example = p.paramName + "_example";
}
example = "'" + escapeText(example) + "'";
} else if ("Integer".equals(type)) {
if (example == null) {
example = "56";
}
} else if ("Float".equals(type)) {
if (example == null) {
example = "3.4";
}
} else if ("BOOLEAN".equals(type)) {
if (example == null) {
example = "true";
}
} else if ("File".equals(type)) {
if (example == null) {
example = "/path/to/file";
}
example = "File.new('" + escapeText(example) + "')";
} else if ("Date".equals(type)) {
if (example == null) {
example = "2013-10-20";
}
example = "Date.parse('" + escapeText(example) + "')";
} else if ("DateTime".equals(type)) {
if (example == null) {
example = "2013-10-20T19:20:30+01:00";
}
example = "DateTime.parse('" + escapeText(example) + "')";
} else if (!languageSpecificPrimitives.contains(type)) {
// type is a model class, e.g. User
example = moduleName + "::" + type + ".new";
}
if (example == null) {
example = "nil";
} else if (Boolean.TRUE.equals(p.isListContainer)) {
example = "[" + example + "]";
} else if (Boolean.TRUE.equals(p.isMapContainer)) {
example = "{'key' => " + example + "}";
}
p.example = example;
}
@Override
public boolean shouldOverwrite(String filename) {
// skip spec file as the file might have been updated with new test cases
return !(skipOverwrite && new File(filename).exists());
//
//return super.shouldOverwrite(filename) && !filename.endsWith("_spec.rb");
}
@Override
public String escapeQuotationMark(String input) {
// remove ' to avoid code injection
return input.replace("'", "");
}
@Override
public String escapeUnsafeCharacters(String input) {
return input.replace("=end", "=_end").replace("=begin", "=_begin");
}
@Override
public void postProcessFile(File file, String fileType) {
if (file == null) {
return;
}
String cPostProcessFile = System.getenv("C_POST_PROCESS_FILE");
if (StringUtils.isEmpty(cPostProcessFile)) {
return; // skip if C_POST_PROCESS_FILE env variable is not defined
}
// only procees the following type (or we can simply rely on the file extension to check if it's a .c or .h file)
Set<String> supportedFileType = new HashSet<String>(
Arrays.asList(
"supporting-mustache",
"model-test",
"model",
"api-test",
"api"));
if (!supportedFileType.contains(fileType)) {
return;
}
// only process files with .c or .h extension
if ("c".equals(FilenameUtils.getExtension(file.toString())) ||
"h".equals(FilenameUtils.getExtension(file.toString()))) {
String command = cPostProcessFile + " " + file.toString();
try {
Process p = Runtime.getRuntime().exec(command);
int exitValue = p.waitFor();
if (exitValue != 0) {
LOGGER.error("Error running the command ({}). Exit code: {}", command, exitValue);
} else {
LOGGER.info("Successfully executed: " + command);
}
} catch (Exception e) {
LOGGER.error("Error running the command ({}). Exception: {}", command, e.getMessage());
}
}
}
}

View File

@@ -285,10 +285,12 @@ public class CSharpNancyFXServerCodegen extends AbstractCSharpCodegen {
LOGGER.debug("Processing parents: " + parentModels);
for (final String parent : parentModels) {
final CodegenModel parentModel = ModelUtils.getModelByName(parent, models);
parentModel.hasChildren = true;
final Collection<CodegenModel> childrenModels = childrenByParent.get(parent);
for (final CodegenModel child : childrenModels) {
processParentPropertiesInChildModel(parentModel, child);
if (parentModel != null) {
parentModel.hasChildren = true;
final Collection<CodegenModel> childrenModels = childrenByParent.get(parent);
for (final CodegenModel child : childrenModels) {
processParentPropertiesInChildModel(parentModel, child);
}
}
}
}

View File

@@ -0,0 +1,850 @@
/*
* Copyright 2018 OpenAPI-Generator Contributors (https://openapi-generator.tech)
* Copyright 2018 SmartBear Software
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.openapitools.codegen.languages;
import static org.apache.commons.lang3.StringUtils.isEmpty;
import com.google.common.collect.ImmutableMap;
import com.samskivert.mustache.Mustache;
import io.swagger.v3.oas.models.media.Schema;
import org.openapitools.codegen.CliOption;
import org.openapitools.codegen.CodegenConstants;
import org.openapitools.codegen.CodegenModel;
import org.openapitools.codegen.CodegenOperation;
import org.openapitools.codegen.CodegenParameter;
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.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
public class CSharpRefactorClientCodegen extends AbstractCSharpCodegen {
@SuppressWarnings({"hiding"})
private static final Logger LOGGER = LoggerFactory.getLogger(CSharpClientCodegen.class);
private static final String NET45 = "v4.5";
private static final String NET40 = "v4.0";
private static final String NET35 = "v3.5";
// TODO: v5.0 is PCL, not netstandard version 1.3, and not a specific .NET Framework. This needs to be updated,
// especially because it will conflict with .NET Framework 5.0 when released, and PCL 5 refers to Framework 4.0.
// We should support either NETSTANDARD, PCL, or Both… but the concepts shouldn't be mixed.
private static final String NETSTANDARD = "v5.0";
private static final String UWP = "uwp";
// Defines the sdk option for targeted frameworks, which differs from targetFramework and targetFrameworkNuget
private static final String MCS_NET_VERSION_KEY = "x-mcs-sdk";
protected String packageGuid = "{" + java.util.UUID.randomUUID().toString().toUpperCase(Locale.ROOT) + "}";
protected String clientPackage = "Org.OpenAPITools.Client";
protected String localVariablePrefix = "";
protected String apiDocPath = "docs/";
protected String modelDocPath = "docs/";
// Defines TargetFrameworkVersion in csproj files
protected String targetFramework = NET45;
// Defines nuget identifiers for target framework
protected String targetFrameworkNuget = "net45";
protected boolean supportsAsync = Boolean.TRUE;
protected boolean supportsUWP = Boolean.FALSE;
protected boolean netStandard = Boolean.FALSE;
protected boolean generatePropertyChanged = Boolean.FALSE;
protected boolean validatable = Boolean.TRUE;
protected Map<Character, String> regexModifiers;
protected final Map<String, String> frameworks;
// By default, generated code is considered public
protected boolean nonPublicApi = Boolean.FALSE;
public CSharpRefactorClientCodegen() {
super();
supportsInheritance = true;
modelTemplateFiles.put("model.mustache", ".cs");
apiTemplateFiles.put("api.mustache", ".cs");
modelDocTemplateFiles.put("model_doc.mustache", ".md");
apiDocTemplateFiles.put("api_doc.mustache", ".md");
embeddedTemplateDir = templateDir = "csharp-refactor";
hideGenerationTimestamp = Boolean.TRUE;
cliOptions.clear();
// CLI options
addOption(CodegenConstants.PACKAGE_NAME,
"C# package name (convention: Title.Case).",
this.packageName);
addOption(CodegenConstants.PACKAGE_VERSION,
"C# package version.",
this.packageVersion);
addOption(CodegenConstants.SOURCE_FOLDER,
CodegenConstants.SOURCE_FOLDER_DESC,
sourceFolder);
addOption(CodegenConstants.OPTIONAL_PROJECT_GUID,
CodegenConstants.OPTIONAL_PROJECT_GUID_DESC,
null);
addOption(CodegenConstants.INTERFACE_PREFIX,
CodegenConstants.INTERFACE_PREFIX_DESC,
interfacePrefix);
CliOption framework = new CliOption(
CodegenConstants.DOTNET_FRAMEWORK,
CodegenConstants.DOTNET_FRAMEWORK_DESC
);
frameworks = new ImmutableMap.Builder<String, String>()
.put(NET35, ".NET Framework 3.5 compatible")
.put(NET40, ".NET Framework 4.0 compatible")
.put(NET45, ".NET Framework 4.5+ compatible")
.put(NETSTANDARD, ".NET Standard 1.3 compatible")
.put(UWP, "Universal Windows Platform (IMPORTANT: this will be decommissioned and replaced by v5.0)")
.build();
framework.defaultValue(this.targetFramework);
framework.setEnum(frameworks);
cliOptions.add(framework);
CliOption modelPropertyNaming = new CliOption(CodegenConstants.MODEL_PROPERTY_NAMING, CodegenConstants.MODEL_PROPERTY_NAMING_DESC);
cliOptions.add(modelPropertyNaming.defaultValue("PascalCase"));
// CLI Switches
addSwitch(CodegenConstants.HIDE_GENERATION_TIMESTAMP,
CodegenConstants.HIDE_GENERATION_TIMESTAMP_DESC,
this.hideGenerationTimestamp);
addSwitch(CodegenConstants.SORT_PARAMS_BY_REQUIRED_FLAG,
CodegenConstants.SORT_PARAMS_BY_REQUIRED_FLAG_DESC,
this.sortParamsByRequiredFlag);
addSwitch(CodegenConstants.USE_DATETIME_OFFSET,
CodegenConstants.USE_DATETIME_OFFSET_DESC,
this.useDateTimeOffsetFlag);
addSwitch(CodegenConstants.USE_COLLECTION,
CodegenConstants.USE_COLLECTION_DESC,
this.useCollection);
addSwitch(CodegenConstants.RETURN_ICOLLECTION,
CodegenConstants.RETURN_ICOLLECTION_DESC,
this.returnICollection);
addSwitch(CodegenConstants.OPTIONAL_METHOD_ARGUMENT,
"C# Optional method argument, e.g. void square(int x=10) (.net 4.0+ only).",
this.optionalMethodArgumentFlag);
addSwitch(CodegenConstants.OPTIONAL_ASSEMBLY_INFO,
CodegenConstants.OPTIONAL_ASSEMBLY_INFO_DESC,
this.optionalAssemblyInfoFlag);
addSwitch(CodegenConstants.OPTIONAL_PROJECT_FILE,
CodegenConstants.OPTIONAL_PROJECT_FILE_DESC,
this.optionalProjectFileFlag);
addSwitch(CodegenConstants.OPTIONAL_EMIT_DEFAULT_VALUES,
CodegenConstants.OPTIONAL_EMIT_DEFAULT_VALUES_DESC,
this.optionalEmitDefaultValue);
addSwitch(CodegenConstants.GENERATE_PROPERTY_CHANGED,
CodegenConstants.PACKAGE_DESCRIPTION_DESC,
this.generatePropertyChanged);
// NOTE: This will reduce visibility of all public members in templates. Users can use InternalsVisibleTo
// https://msdn.microsoft.com/en-us/library/system.runtime.compilerservices.internalsvisibletoattribute(v=vs.110).aspx
// to expose to shared code if the generated code is not embedded into another project. Otherwise, users of codegen
// should rely on default public visibility.
addSwitch(CodegenConstants.NON_PUBLIC_API,
CodegenConstants.NON_PUBLIC_API_DESC,
this.nonPublicApi);
addSwitch(CodegenConstants.ALLOW_UNICODE_IDENTIFIERS,
CodegenConstants.ALLOW_UNICODE_IDENTIFIERS_DESC,
this.allowUnicodeIdentifiers);
addSwitch(CodegenConstants.NETCORE_PROJECT_FILE,
CodegenConstants.NETCORE_PROJECT_FILE_DESC,
this.netCoreProjectFileFlag);
addSwitch(CodegenConstants.VALIDATABLE,
CodegenConstants.VALIDATABLE_DESC,
this.validatable);
regexModifiers = new HashMap<Character, String>();
regexModifiers.put('i', "IgnoreCase");
regexModifiers.put('m', "Multiline");
regexModifiers.put('s', "Singleline");
regexModifiers.put('x', "IgnorePatternWhitespace");
}
@Override
public void processOpts() {
super.processOpts();
/*
* NOTE: When supporting boolean additionalProperties, you should read the value and write it back as a boolean.
* This avoids oddities where additionalProperties contains "false" rather than false, which will cause the
* templating engine to behave unexpectedly.
*
* Use the pattern:
* if (additionalProperties.containsKey(prop)) convertPropertyToBooleanAndWriteBack(prop);
*/
if (additionalProperties.containsKey(CodegenConstants.MODEL_PROPERTY_NAMING)) {
setModelPropertyNaming((String) additionalProperties.get(CodegenConstants.MODEL_PROPERTY_NAMING));
}
if (isEmpty(apiPackage)) {
setApiPackage("Api");
}
if (isEmpty(modelPackage)) {
setModelPackage("Model");
}
clientPackage = "Client";
Boolean excludeTests = false;
if (additionalProperties.containsKey(CodegenConstants.EXCLUDE_TESTS)) {
excludeTests = convertPropertyToBooleanAndWriteBack(CodegenConstants.EXCLUDE_TESTS);
}
if (additionalProperties.containsKey(CodegenConstants.VALIDATABLE)) {
setValidatable(convertPropertyToBooleanAndWriteBack(CodegenConstants.VALIDATABLE));
} else {
additionalProperties.put(CodegenConstants.VALIDATABLE, validatable);
}
if (additionalProperties.containsKey(CodegenConstants.DOTNET_FRAMEWORK)) {
setTargetFramework((String) additionalProperties.get(CodegenConstants.DOTNET_FRAMEWORK));
} else {
// Ensure default is set.
setTargetFramework(NET45);
additionalProperties.put(CodegenConstants.DOTNET_FRAMEWORK, this.targetFramework);
}
if (NET35.equals(this.targetFramework)) {
// This is correct, mono will require you build .NET 3.5 sources using 4.0 SDK
additionalProperties.put(MCS_NET_VERSION_KEY, "4");
additionalProperties.put("net35", true);
if (additionalProperties.containsKey(CodegenConstants.SUPPORTS_ASYNC)) {
LOGGER.warn(".NET 3.5 generator does not support async.");
additionalProperties.remove(CodegenConstants.SUPPORTS_ASYNC);
}
setTargetFrameworkNuget("net35");
setValidatable(Boolean.FALSE);
setSupportsAsync(Boolean.FALSE);
} else if (NETSTANDARD.equals(this.targetFramework)) {
// TODO: NETSTANDARD here is misrepresenting a PCL v5.0 which supports .NET Framework 4.6+, .NET Core 1.0, and Windows Universal 10.0
additionalProperties.put(MCS_NET_VERSION_KEY, "4.6-api");
if (additionalProperties.containsKey("supportsUWP")) {
LOGGER.warn(".NET " + NETSTANDARD + " generator does not support UWP.");
additionalProperties.remove("supportsUWP");
}
// TODO: NETSTANDARD=v5.0 and targetFrameworkNuget=netstandard1.3. These need to sync.
setTargetFrameworkNuget("netstandard1.3");
setSupportsAsync(Boolean.TRUE);
setSupportsUWP(Boolean.FALSE);
setNetStandard(Boolean.TRUE);
//Tests not yet implemented for .NET Standard codegen
//Todo implement it
excludeTests = true;
} else if (UWP.equals(this.targetFramework)) {
setTargetFrameworkNuget("uwp");
setSupportsAsync(Boolean.TRUE);
setSupportsUWP(Boolean.TRUE);
} else if (NET40.equals(this.targetFramework)) {
additionalProperties.put(MCS_NET_VERSION_KEY, "4");
additionalProperties.put("isNet40", true);
if (additionalProperties.containsKey(CodegenConstants.SUPPORTS_ASYNC)) {
LOGGER.warn(".NET " + NET40 + " generator does not support async.");
additionalProperties.remove(CodegenConstants.SUPPORTS_ASYNC);
}
setTargetFrameworkNuget("net40");
setSupportsAsync(Boolean.FALSE);
} else {
additionalProperties.put(MCS_NET_VERSION_KEY, "4.5.2-api");
setTargetFrameworkNuget("net45");
setSupportsAsync(Boolean.TRUE);
}
if (additionalProperties.containsKey(CodegenConstants.GENERATE_PROPERTY_CHANGED)) {
if (NET35.equals(targetFramework)) {
LOGGER.warn(CodegenConstants.GENERATE_PROPERTY_CHANGED + " is only supported by generated code for .NET 4+.");
additionalProperties.remove(CodegenConstants.GENERATE_PROPERTY_CHANGED);
} else if (NETSTANDARD.equals(targetFramework)) {
LOGGER.warn(CodegenConstants.GENERATE_PROPERTY_CHANGED + " is not supported in .NET Standard generated code.");
additionalProperties.remove(CodegenConstants.GENERATE_PROPERTY_CHANGED);
} else if (Boolean.TRUE.equals(netCoreProjectFileFlag)) {
LOGGER.warn(CodegenConstants.GENERATE_PROPERTY_CHANGED + " is not supported in .NET Core csproj project format.");
additionalProperties.remove(CodegenConstants.GENERATE_PROPERTY_CHANGED);
} else {
setGeneratePropertyChanged(convertPropertyToBooleanAndWriteBack(CodegenConstants.GENERATE_PROPERTY_CHANGED));
}
}
additionalProperties.put(CodegenConstants.API_PACKAGE, apiPackage);
additionalProperties.put(CodegenConstants.MODEL_PACKAGE, modelPackage);
additionalProperties.put("clientPackage", clientPackage);
additionalProperties.put(CodegenConstants.EXCLUDE_TESTS, excludeTests);
additionalProperties.put(CodegenConstants.VALIDATABLE, this.validatable);
additionalProperties.put(CodegenConstants.SUPPORTS_ASYNC, this.supportsAsync);
additionalProperties.put("supportsUWP", this.supportsUWP);
additionalProperties.put("netStandard", this.netStandard);
additionalProperties.put("targetFrameworkNuget", this.targetFrameworkNuget);
// TODO: either remove this and update templates to match the "optionalEmitDefaultValues" property, or rename that property.
additionalProperties.put("emitDefaultValue", optionalEmitDefaultValue);
if (additionalProperties.containsKey(CodegenConstants.OPTIONAL_PROJECT_FILE)) {
setOptionalProjectFileFlag(convertPropertyToBooleanAndWriteBack(CodegenConstants.OPTIONAL_PROJECT_FILE));
} else {
additionalProperties.put(CodegenConstants.OPTIONAL_PROJECT_FILE, optionalProjectFileFlag);
}
if (additionalProperties.containsKey(CodegenConstants.OPTIONAL_PROJECT_GUID)) {
setPackageGuid((String) additionalProperties.get(CodegenConstants.OPTIONAL_PROJECT_GUID));
} else {
additionalProperties.put(CodegenConstants.OPTIONAL_PROJECT_GUID, packageGuid);
}
if (additionalProperties.containsKey(CodegenConstants.OPTIONAL_METHOD_ARGUMENT)) {
setOptionalMethodArgumentFlag(convertPropertyToBooleanAndWriteBack(CodegenConstants.OPTIONAL_METHOD_ARGUMENT));
} else {
additionalProperties.put(CodegenConstants.OPTIONAL_METHOD_ARGUMENT, optionalMethodArgumentFlag);
}
if (additionalProperties.containsKey(CodegenConstants.OPTIONAL_ASSEMBLY_INFO)) {
setOptionalAssemblyInfoFlag(convertPropertyToBooleanAndWriteBack(CodegenConstants.OPTIONAL_ASSEMBLY_INFO));
} else {
additionalProperties.put(CodegenConstants.OPTIONAL_ASSEMBLY_INFO, optionalAssemblyInfoFlag);
}
if (additionalProperties.containsKey(CodegenConstants.NON_PUBLIC_API)) {
setNonPublicApi(convertPropertyToBooleanAndWriteBack(CodegenConstants.NON_PUBLIC_API));
} else {
additionalProperties.put(CodegenConstants.NON_PUBLIC_API, isNonPublicApi());
}
final String testPackageName = testPackageName();
String packageFolder = sourceFolder + File.separator + packageName;
String clientPackageDir = packageFolder + File.separator + clientPackage;
String testPackageFolder = testFolder + File.separator + testPackageName;
additionalProperties.put("testPackageName", testPackageName);
//Compute the relative path to the bin directory where the external assemblies live
//This is necessary to properly generate the project file
int packageDepth = packageFolder.length() - packageFolder.replace(java.io.File.separator, "").length();
String binRelativePath = "..\\";
for (int i = 0; i < packageDepth; i = i + 1)
binRelativePath += "..\\";
binRelativePath += "vendor";
additionalProperties.put("binRelativePath", binRelativePath);
supportingFiles.add(new SupportingFile("IApiAccessor.mustache",
clientPackageDir, "IApiAccessor.cs"));
supportingFiles.add(new SupportingFile("Configuration.mustache",
clientPackageDir, "Configuration.cs"));
supportingFiles.add(new SupportingFile("ApiClient.mustache",
clientPackageDir, "ApiClient.cs"));
supportingFiles.add(new SupportingFile("ApiException.mustache",
clientPackageDir, "ApiException.cs"));
supportingFiles.add(new SupportingFile("ApiResponse.mustache",
clientPackageDir, "ApiResponse.cs"));
supportingFiles.add(new SupportingFile("ExceptionFactory.mustache",
clientPackageDir, "ExceptionFactory.cs"));
supportingFiles.add(new SupportingFile("OpenAPIDateConverter.mustache",
clientPackageDir, "OpenAPIDateConverter.cs"));
supportingFiles.add(new SupportingFile("ClientUtils.mustache",
clientPackageDir, "ClientUtils.cs"));
supportingFiles.add(new SupportingFile("HttpMethod.mustache",
clientPackageDir, "HttpMethod.cs"));
supportingFiles.add(new SupportingFile("IAsynchronousClient.mustache",
clientPackageDir, "IAsynchronousClient.cs"));
supportingFiles.add(new SupportingFile("ISynchronousClient.mustache",
clientPackageDir, "ISynchronousClient.cs"));
supportingFiles.add(new SupportingFile("RequestOptions.mustache",
clientPackageDir, "RequestOptions.cs"));
supportingFiles.add(new SupportingFile("Multimap.mustache",
clientPackageDir, "Multimap.cs"));
if (Boolean.FALSE.equals(this.netStandard) && Boolean.FALSE.equals(this.netCoreProjectFileFlag)) {
supportingFiles.add(new SupportingFile("compile.mustache", "", "build.bat"));
supportingFiles.add(new SupportingFile("compile-mono.sh.mustache", "", "build.sh"));
// copy package.config to nuget's standard location for project-level installs
supportingFiles.add(new SupportingFile("packages.config.mustache", packageFolder + File.separator, "packages.config"));
// .travis.yml for travis-ci.org CI
supportingFiles.add(new SupportingFile("travis.mustache", "", ".travis.yml"));
} else if (Boolean.FALSE.equals(this.netCoreProjectFileFlag)) {
supportingFiles.add(new SupportingFile("project.json.mustache", packageFolder + File.separator, "project.json"));
}
supportingFiles.add(new SupportingFile("IReadableConfiguration.mustache",
clientPackageDir, "IReadableConfiguration.cs"));
supportingFiles.add(new SupportingFile("GlobalConfiguration.mustache",
clientPackageDir, "GlobalConfiguration.cs"));
// Only write out test related files if excludeTests is unset or explicitly set to false (see start of this method)
if (Boolean.FALSE.equals(excludeTests)) {
// shell script to run the nunit test
supportingFiles.add(new SupportingFile("mono_nunit_test.mustache", "", "mono_nunit_test.sh"));
modelTestTemplateFiles.put("model_test.mustache", ".cs");
apiTestTemplateFiles.put("api_test.mustache", ".cs");
if (Boolean.FALSE.equals(this.netCoreProjectFileFlag)) {
supportingFiles.add(new SupportingFile("packages_test.config.mustache", testPackageFolder + File.separator, "packages.config"));
}
if (NET40.equals(this.targetFramework)) {
// Include minimal tests for modifications made to JsonSubTypes, since code is quite different for .net 4.0 from original implementation
supportingFiles.add(new SupportingFile("JsonSubTypesTests.mustache",
testPackageFolder + File.separator + "Client",
"JsonSubTypesTests.cs"));
}
}
if (Boolean.TRUE.equals(generatePropertyChanged)) {
supportingFiles.add(new SupportingFile("FodyWeavers.xml", packageFolder, "FodyWeavers.xml"));
}
supportingFiles.add(new SupportingFile("README.mustache", "", "README.md"));
supportingFiles.add(new SupportingFile("git_push.sh.mustache", "", "git_push.sh"));
supportingFiles.add(new SupportingFile("gitignore.mustache", "", ".gitignore"));
if (optionalAssemblyInfoFlag && Boolean.FALSE.equals(this.netCoreProjectFileFlag)) {
supportingFiles.add(new SupportingFile("AssemblyInfo.mustache", packageFolder + File.separator + "Properties", "AssemblyInfo.cs"));
}
if (optionalProjectFileFlag) {
supportingFiles.add(new SupportingFile("Solution.mustache", "", packageName + ".sln"));
if (Boolean.TRUE.equals(this.netCoreProjectFileFlag)) {
supportingFiles.add(new SupportingFile("netcore_project.mustache", packageFolder, packageName + ".csproj"));
} else {
supportingFiles.add(new SupportingFile("Project.mustache", packageFolder, packageName + ".csproj"));
if (Boolean.FALSE.equals(this.netStandard)) {
supportingFiles.add(new SupportingFile("nuspec.mustache", packageFolder, packageName + ".nuspec"));
}
}
if (Boolean.FALSE.equals(excludeTests)) {
// NOTE: This exists here rather than previous excludeTests block because the test project is considered an optional project file.
if (Boolean.TRUE.equals(this.netCoreProjectFileFlag)) {
supportingFiles.add(new SupportingFile("netcore_testproject.mustache", testPackageFolder, testPackageName + ".csproj"));
} else {
supportingFiles.add(new SupportingFile("TestProject.mustache", testPackageFolder, testPackageName + ".csproj"));
}
}
}
additionalProperties.put("apiDocPath", apiDocPath);
additionalProperties.put("modelDocPath", modelDocPath);
}
public void setModelPropertyNaming(String naming) {
if ("original".equals(naming) || "camelCase".equals(naming) ||
"PascalCase".equals(naming) || "snake_case".equals(naming)) {
this.modelPropertyNaming = naming;
} else {
throw new IllegalArgumentException("Invalid model property naming '" +
naming + "'. Must be 'original', 'camelCase', " +
"'PascalCase' or 'snake_case'");
}
}
public String getModelPropertyNaming() {
return this.modelPropertyNaming;
}
@Override
public Map<String, Object> postProcessOperationsWithModels(Map<String, Object> objs, List<Object> allModels) {
super.postProcessOperationsWithModels(objs, allModels);
if (objs != null) {
Map<String, Object> operations = (Map<String, Object>) objs.get("operations");
if (operations != null) {
List<CodegenOperation> ops = (List<CodegenOperation>) operations.get("operation");
for (CodegenOperation operation : ops) {
if (operation.returnType != null) {
operation.returnContainer = operation.returnType;
if (this.returnICollection && (
operation.returnType.startsWith("List") ||
operation.returnType.startsWith("Collection"))) {
// NOTE: ICollection works for both List<T> and Collection<T>
int genericStart = operation.returnType.indexOf("<");
if (genericStart > 0) {
operation.returnType = "ICollection" + operation.returnType.substring(genericStart);
}
}
}
}
}
}
return objs;
}
@Override
public CodegenType getTag() {
return CodegenType.CLIENT;
}
@Override
public String getName() {
return "csharp-refactor";
}
@Override
public String getHelp() {
return "Generates a CSharp client library.";
}
public void setOptionalAssemblyInfoFlag(boolean flag) {
this.optionalAssemblyInfoFlag = flag;
}
@Override
public CodegenModel fromModel(String name, Schema model, Map<String, Schema> allDefinitions) {
CodegenModel codegenModel = super.fromModel(name, model, allDefinitions);
if (allDefinitions != null && codegenModel != null && codegenModel.parent != null) {
final Schema parentModel = allDefinitions.get(toModelName(codegenModel.parent));
if (parentModel != null) {
final CodegenModel parentCodegenModel = super.fromModel(codegenModel.parent, parentModel, allDefinitions);
if (codegenModel.hasEnums) {
codegenModel = this.reconcileInlineEnums(codegenModel, parentCodegenModel);
}
Map<String, CodegenProperty> propertyHash = new HashMap<>(codegenModel.vars.size());
for (final CodegenProperty property : codegenModel.vars) {
propertyHash.put(property.name, property);
}
for (final CodegenProperty property : codegenModel.readWriteVars) {
if (property.defaultValue == null && property.baseName.equals(parentCodegenModel.discriminator)) {
property.defaultValue = "\"" + name + "\"";
}
}
CodegenProperty last = null;
for (final CodegenProperty property : parentCodegenModel.vars) {
// helper list of parentVars simplifies templating
if (!propertyHash.containsKey(property.name)) {
final CodegenProperty parentVar = property.clone();
parentVar.isInherited = true;
parentVar.hasMore = true;
last = parentVar;
LOGGER.info("adding parent variable {}", property.name);
codegenModel.parentVars.add(parentVar);
}
}
if (last != null) {
last.hasMore = false;
}
}
}
// Cleanup possible duplicates. Currently, readWriteVars can contain the same property twice. May or may not be isolated to C#.
if (codegenModel != null && codegenModel.readWriteVars != null && codegenModel.readWriteVars.size() > 1) {
int length = codegenModel.readWriteVars.size() - 1;
for (int i = length; i > (length / 2); i--) {
final CodegenProperty codegenProperty = codegenModel.readWriteVars.get(i);
// If the property at current index is found earlier in the list, remove this last instance.
if (codegenModel.readWriteVars.indexOf(codegenProperty) < i) {
codegenModel.readWriteVars.remove(i);
}
}
}
return codegenModel;
}
public void setOptionalProjectFileFlag(boolean flag) {
this.optionalProjectFileFlag = flag;
}
public void setPackageGuid(String packageGuid) {
this.packageGuid = packageGuid;
}
@Override
public void postProcessParameter(CodegenParameter parameter) {
postProcessPattern(parameter.pattern, parameter.vendorExtensions);
super.postProcessParameter(parameter);
}
@Override
public void postProcessModelProperty(CodegenModel model, CodegenProperty property) {
postProcessPattern(property.pattern, property.vendorExtensions);
super.postProcessModelProperty(model, property);
}
/*
* The pattern spec follows the Perl convention and style of modifiers. .NET
* does not support this syntax directly so we need to convert the pattern to a .NET compatible
* format and apply modifiers in a compatible way.
* See https://msdn.microsoft.com/en-us/library/yd1hzczs(v=vs.110).aspx for .NET options.
*/
public void postProcessPattern(String pattern, Map<String, Object> vendorExtensions) {
if (pattern != null) {
int i = pattern.lastIndexOf('/');
//Must follow Perl /pattern/modifiers convention
if (pattern.charAt(0) != '/' || i < 2) {
throw new IllegalArgumentException("Pattern must follow the Perl "
+ "/pattern/modifiers convention. " + pattern + " is not valid.");
}
String regex = pattern.substring(1, i).replace("'", "\'");
List<String> modifiers = new ArrayList<String>();
// perl requires an explicit modifier to be culture specific and .NET is the reverse.
modifiers.add("CultureInvariant");
for (char c : pattern.substring(i).toCharArray()) {
if (regexModifiers.containsKey(c)) {
String modifier = regexModifiers.get(c);
modifiers.add(modifier);
} else if (c == 'l') {
modifiers.remove("CultureInvariant");
}
}
vendorExtensions.put("x-regex", regex);
vendorExtensions.put("x-modifiers", modifiers);
}
}
public void setTargetFramework(String dotnetFramework) {
if (!frameworks.containsKey(dotnetFramework)) {
LOGGER.warn("Invalid .NET framework version, defaulting to " + this.targetFramework);
} else {
this.targetFramework = dotnetFramework;
}
LOGGER.info("Generating code for .NET Framework " + this.targetFramework);
}
private CodegenModel reconcileInlineEnums(CodegenModel codegenModel, CodegenModel parentCodegenModel) {
// This generator uses inline classes to define enums, which breaks when
// dealing with models that have subTypes. To clean this up, we will analyze
// the parent and child models, look for enums that match, and remove
// them from the child models and leave them in the parent.
// Because the child models extend the parents, the enums will be available via the parent.
// Only bother with reconciliation if the parent model has enums.
if (parentCodegenModel.hasEnums) {
// Get the properties for the parent and child models
final List<CodegenProperty> parentModelCodegenProperties = parentCodegenModel.vars;
List<CodegenProperty> codegenProperties = codegenModel.vars;
// Iterate over all of the parent model properties
boolean removedChildEnum = false;
for (CodegenProperty parentModelCodegenPropery : parentModelCodegenProperties) {
// Look for enums
if (parentModelCodegenPropery.isEnum) {
// Now that we have found an enum in the parent class,
// and search the child class for the same enum.
Iterator<CodegenProperty> iterator = codegenProperties.iterator();
while (iterator.hasNext()) {
CodegenProperty codegenProperty = iterator.next();
if (codegenProperty.isEnum && codegenProperty.equals(parentModelCodegenPropery)) {
// We found an enum in the child class that is
// a duplicate of the one in the parent, so remove it.
iterator.remove();
removedChildEnum = true;
}
}
}
}
if (removedChildEnum) {
// If we removed an entry from this model's vars, we need to ensure hasMore is updated
int count = 0, numVars = codegenProperties.size();
for (CodegenProperty codegenProperty : codegenProperties) {
count += 1;
codegenProperty.hasMore = count < numVars;
}
codegenModel.vars = codegenProperties;
}
}
return codegenModel;
}
@Override
public String toEnumVarName(String value, String datatype) {
if (value.length() == 0) {
return "Empty";
}
// for symbol, e.g. $, #
if (getSymbolName(value) != null) {
return camelize(getSymbolName(value));
}
// number
if (datatype.startsWith("int") || datatype.startsWith("long") ||
datatype.startsWith("double") || datatype.startsWith("float")) {
String varName = "NUMBER_" + value;
varName = varName.replaceAll("-", "MINUS_");
varName = varName.replaceAll("\\+", "PLUS_");
varName = varName.replaceAll("\\.", "_DOT_");
return varName;
}
// string
String var = value.replaceAll("_", " ");
//var = WordUtils.capitalizeFully(var);
var = camelize(var);
var = var.replaceAll("\\W+", "");
if (var.matches("\\d.*")) {
return "_" + var;
} else {
return var;
}
}
@Override
public String toVarName(String name) {
// sanitize name
name = sanitizeName(name);
// if it's all uppper case, do nothing
if (name.matches("^[A-Z_]*$")) {
return name;
}
name = getNameUsingModelPropertyNaming(name);
// for reserved word or word starting with number, append _
if (isReservedWord(name) || name.matches("^\\d.*")) {
name = escapeReservedWord(name);
}
return name;
}
public String getNameUsingModelPropertyNaming(String name) {
switch (CodegenConstants.MODEL_PROPERTY_NAMING_TYPE.valueOf(getModelPropertyNaming())) {
case original:
return name;
case camelCase:
return camelize(name, true);
case PascalCase:
return camelize(name);
case snake_case:
return underscore(name);
default:
throw new IllegalArgumentException("Invalid model property naming '" +
name + "'. Must be 'original', 'camelCase', " +
"'PascalCase' or 'snake_case'");
}
}
public void setPackageName(String packageName) {
this.packageName = packageName;
}
public void setPackageVersion(String packageVersion) {
this.packageVersion = packageVersion;
}
public void setTargetFrameworkNuget(String targetFrameworkNuget) {
this.targetFrameworkNuget = targetFrameworkNuget;
}
public void setSupportsAsync(Boolean supportsAsync) {
this.supportsAsync = supportsAsync;
}
public void setSupportsUWP(Boolean supportsUWP) {
this.supportsUWP = supportsUWP;
}
public void setNetStandard(Boolean netStandard) {
this.netStandard = netStandard;
}
public void setGeneratePropertyChanged(final Boolean generatePropertyChanged) {
this.generatePropertyChanged = generatePropertyChanged;
}
public boolean isNonPublicApi() {
return nonPublicApi;
}
public void setNonPublicApi(final boolean nonPublicApi) {
this.nonPublicApi = nonPublicApi;
}
public void setValidatable(boolean validatable) {
this.validatable = validatable;
}
@Override
public String toModelDocFilename(String name) {
return toModelFilename(name);
}
@Override
public String apiDocFileFolder() {
return (outputFolder + "/" + apiDocPath).replace('/', File.separatorChar);
}
@Override
public String modelDocFileFolder() {
return (outputFolder + "/" + modelDocPath).replace('/', File.separatorChar);
}
@Override
public String apiTestFileFolder() {
return outputFolder + File.separator + testFolder + File.separator + testPackageName() + File.separator + apiPackage();
}
@Override
public String modelTestFileFolder() {
return outputFolder + File.separator + testFolder + File.separator + testPackageName() + File.separator + modelPackage();
}
@Override
public Mustache.Compiler processCompiler(Mustache.Compiler compiler) {
// To avoid unexpected behaviors when options are passed programmatically such as { "supportsAsync": "" }
return super.processCompiler(compiler).emptyStringIsFalse(true);
}
}

View File

@@ -253,7 +253,7 @@ public class CppQt5ClientCodegen extends AbstractCppCodegen implements CodegenCo
if (!folder.isEmpty())
folder += File.separator;
return "#include \"" + folder + toModelName(name) + ".h\"";
return "#include \"" + folder + sanitizeName(name) + ".h\"";
}
/**
@@ -276,12 +276,12 @@ public class CppQt5ClientCodegen extends AbstractCppCodegen implements CodegenCo
@Override
public String toModelFilename(String name) {
return initialCaps(toModelName(name));
return sanitizeName(initialCaps(toModelName(name)));
}
@Override
public String toApiFilename(String name) {
return modelNamePrefix + initialCaps(name) + "Api";
return modelNamePrefix + sanitizeName(initialCaps(name)) + "Api";
}
/**

View File

@@ -306,7 +306,7 @@ public class CppQt5QHttpEngineServerCodegen extends AbstractCppCodegen implement
@Override
public String toModelFilename(String name) {
return modelNamePrefix + initialCaps(name);
return modelNamePrefix + sanitizeName(initialCaps(name));
}
@Override
@@ -322,7 +322,7 @@ public class CppQt5QHttpEngineServerCodegen extends AbstractCppCodegen implement
@Override
public String toApiFilename(String name) {
return modelNamePrefix + initialCaps(name) + "ApiHandler";
return modelNamePrefix + sanitizeName(initialCaps(name)) + "ApiHandler";
}
/**

View File

@@ -285,8 +285,8 @@ public class CppRestSdkClientCodegen extends AbstractCppCodegen {
Map<String, Object> operations = (Map<String, Object>) objs.get("operations");
List<CodegenOperation> operationList = (List<CodegenOperation>) operations.get("operation");
for (CodegenOperation op : operationList) {
for(String hdr : op.imports) {
if(importMapping.containsKey(hdr)) {
for (String hdr : op.imports) {
if (importMapping.containsKey(hdr)) {
continue;
}
operations.put("hasModelImport", true);
@@ -295,7 +295,7 @@ public class CppRestSdkClientCodegen extends AbstractCppCodegen {
}
return objs;
}
protected boolean isFileSchema(CodegenProperty property) {
return property.baseType.equals("HttpContent");
}
@@ -411,7 +411,6 @@ public class CppRestSdkClientCodegen extends AbstractCppCodegen {
@Override
public Map<String, Object> postProcessAllModels(final Map<String, Object> models) {
final Map<String, Object> processed = super.postProcessAllModels(models);
postProcessParentModels(models);
return processed;
@@ -432,13 +431,18 @@ public class CppRestSdkClientCodegen extends AbstractCppCodegen {
*/
private void processParentPropertiesInChildModel(final CodegenModel parent, final CodegenModel child) {
final Map<String, CodegenProperty> childPropertiesByName = new HashMap<>(child.vars.size());
for (final CodegenProperty childSchema : child.vars) {
childPropertiesByName.put(childSchema.name, childSchema);
if (child != null && child.vars != null && !child.vars.isEmpty()) {
for (final CodegenProperty childSchema : child.vars) {
childPropertiesByName.put(childSchema.name, childSchema);
}
}
for (final CodegenProperty parentSchema : parent.vars) {
final CodegenProperty duplicatedByParent = childPropertiesByName.get(parentSchema.name);
if (duplicatedByParent != null) {
duplicatedByParent.isInherited = true;
if (parent != null && parent.vars != null && !parent.vars.isEmpty()) {
for (final CodegenProperty parentSchema : parent.vars) {
final CodegenProperty duplicatedByParent = childPropertiesByName.get(parentSchema.name);
if (duplicatedByParent != null) {
duplicatedByParent.isInherited = true;
}
}
}
}

View File

@@ -152,6 +152,7 @@ public class DartClientCodegen extends DefaultCodegen implements CodegenConfig {
if (StringUtils.isEmpty(System.getenv("DART_POST_PROCESS_FILE"))) {
LOGGER.info("Environment variable DART_POST_PROCESS_FILE not defined so the Dart code may not be properly formatted. To define it, try `export DART_POST_PROCESS_FILE=\"/usr/local/bin/dartfmt -w\"` (Linux/Mac)");
LOGGER.info("NOTE: To enable file post-processing, 'enablePostProcessFile' must be set to `true` (--enable-post-process-file for CLI).");
}
if (additionalProperties.containsKey(BROWSER_CLIENT)) {
@@ -313,6 +314,9 @@ public class DartClientCodegen extends DefaultCodegen implements CodegenConfig {
}
if (schema.getDefault() != null) {
if (ModelUtils.isStringSchema(schema)) {
return "\"" + schema.getDefault().toString().replaceAll("\"", "\\\"") + "\"";
}
return schema.getDefault().toString();
} else {
return "null";

View File

@@ -169,7 +169,7 @@ public class ElixirClientCodegen extends DefaultCodegen implements CodegenConfig
typeMapping.put("map", "Map");
typeMapping.put("array", "List");
typeMapping.put("list", "List");
// typeMapping.put("object", "Map");
typeMapping.put("object", "Map");
typeMapping.put("binary", "String");
typeMapping.put("ByteArray", "String");
typeMapping.put("UUID", "String");
@@ -431,7 +431,19 @@ public class ElixirClientCodegen extends DefaultCodegen implements CodegenConfig
throw new RuntimeException("Empty method name (operationId) not allowed");
}
return org.openapitools.codegen.utils.StringUtils.camelize(sanitizeName(operationId));
// method name cannot use reserved keyword, e.g. return
if (isReservedWord(operationId)) {
LOGGER.warn(operationId + " (reserved word) cannot be used as method name. Renamed to " + org.openapitools.codegen.utils.StringUtils.underscore(sanitizeName("call_" + operationId)));
return org.openapitools.codegen.utils.StringUtils.underscore(sanitizeName("call_" + operationId));
}
// operationId starts with a number
if (operationId.matches("^\\d.*")) {
LOGGER.warn(operationId + " (starting with a number) cannot be used as method name. Renamed to " + org.openapitools.codegen.utils.StringUtils.underscore(sanitizeName("call_" + operationId)));
operationId = "call_" + operationId;
}
return org.openapitools.codegen.utils.StringUtils.underscore(sanitizeName(operationId));
}
/**
@@ -642,6 +654,9 @@ public class ElixirClientCodegen extends DefaultCodegen implements CodegenConfig
sb.append(param.dataType);
} else if (param.isFile || param.isBinary) {
sb.append("String.t");
} else if ("String.t".equals(param.dataType)) {
// uuid, password, etc
sb.append(param.dataType);
} else {
// <module>.Model.<type>.t
sb.append(moduleName);
@@ -681,6 +696,8 @@ public class ElixirClientCodegen extends DefaultCodegen implements CodegenConfig
// Primitive return type, don't even try to decode
if (returnBaseType == null || (returnSimpleType && returnTypeIsPrimitive)) {
return "false";
} else if (isListContainer && languageSpecificPrimitives().contains(returnBaseType)) {
return "[]";
}
StringBuilder sb = new StringBuilder();
if (isListContainer) {

View File

@@ -66,7 +66,7 @@ public class ElmClientCodegen extends DefaultCodegen implements CodegenConfig {
private static final String ENCODER = "elmEncoder";
private static final String DECODER = "elmDecoder";
private static final String DISCRIMINATOR_NAME = "discriminatorName";
private static final String UNION_TYPE = "elmUnionType";
private static final String CUSTOM_TYPE = "elmCustomType";
protected String packageName = "openapi";
protected String packageVersion = "1.0.0";
@@ -123,6 +123,7 @@ public class ElmClientCodegen extends DefaultCodegen implements CodegenConfig {
"Dict",
"Float",
"Int",
"List",
"String")
);
@@ -191,6 +192,7 @@ public class ElmClientCodegen extends DefaultCodegen implements CodegenConfig {
} else { // 0.19
LOGGER.info("Environment variable ELM_POST_PROCESS_FILE not defined so the Elm code may not be properly formatted. To define it, try `export ELM_POST_PROCESS_FILE=\"/usr/local/bin/elm-format --elm-version={} --yes\"` (Linux/Mac)", "0.19");
}
LOGGER.info("NOTE: To enable file post-processing, 'enablePostProcessFile' must be set to `true` (--enable-post-process-file for CLI).");
}
switch (elmVersion) {
@@ -261,7 +263,13 @@ public class ElmClientCodegen extends DefaultCodegen implements CodegenConfig {
@Override
public String toEnumVarName(String value, String datatype) {
final String camelized = org.openapitools.codegen.utils.StringUtils.camelize(value.replace(" ", "_").replace("(", "_").replace(")", "")); // TODO FIXME escape properly
String camelized = org.openapitools.codegen.utils.StringUtils.camelize(value.replace(" ", "_").replace("(", "_").replace(")", "")); // TODO FIXME escape properly
if (camelized.length() == 0) {
LOGGER.error("Unable to determine enum variable name (name: {}, datatype: {}) from empty string. Default to UnknownEnumVariableName", value, datatype);
camelized = "UnknownEnumVariableName";
}
if (!Character.isUpperCase(camelized.charAt(0))) {
return "N" + camelized;
}
@@ -345,7 +353,7 @@ public class ElmClientCodegen extends DefaultCodegen implements CodegenConfig {
CodegenModel cm = (CodegenModel) mo.get("model");
if (cm.isEnum) {
addEncoderAndDecoder(cm.vendorExtensions, cm.classname, DataTypeExposure.EXPOSED);
cm.vendorExtensions.put(UNION_TYPE, cm.classname);
cm.vendorExtensions.put(CUSTOM_TYPE, cm.classname);
} else if (cm.isAlias) {
addEncoderAndDecoder(cm.vendorExtensions, cm.dataType, DataTypeExposure.EXPOSED);
}
@@ -495,9 +503,8 @@ public class ElmClientCodegen extends DefaultCodegen implements CodegenConfig {
} else if (ModelUtils.isDateTimeSchema(p)) {
return toOptionalValue(null);
} else if (ModelUtils.isNumberSchema(p)) {
NumberSchema dp = (NumberSchema) p;
if (dp.getDefault() != null) {
return toOptionalValue(dp.getDefault().toString());
if (p.getDefault() != null) {
return toOptionalValue(p.getDefault().toString());
}
return toOptionalValue(null);
} else if (ModelUtils.isIntegerSchema(p)) {
@@ -572,7 +579,7 @@ public class ElmClientCodegen extends DefaultCodegen implements CodegenConfig {
if (property.isEnum) {
addEncoderAndDecoder(property.vendorExtensions, property.baseName, DataTypeExposure.INTERNAL);
property.vendorExtensions.put(UNION_TYPE, property.datatypeWithEnum);
property.vendorExtensions.put(CUSTOM_TYPE, property.datatypeWithEnum);
} else {
final boolean isPrimitiveType = property.isMapContainer ? isPrimitiveDataType(property.dataType) : property.isPrimitiveType;
addEncoderAndDecoder(property.vendorExtensions, property.dataType, isPrimitiveType ? DataTypeExposure.PRIMITIVE : DataTypeExposure.EXTERNAL);

View File

@@ -891,7 +891,7 @@ public class HaskellHttpClientCodegen extends DefaultCodegen implements CodegenC
if (appendDataType
&& uniqueParamNameTypes.containsKey(paramNameType)
&& !isDuplicate(paramNameType, dataType)) {
paramNameType = paramNameType + dataType;
paramNameType = toTypeName("", paramNameType + dataType);
}
while (typeNames.contains(paramNameType)) {

View File

@@ -152,6 +152,7 @@ public class JavaResteasyServerCodegen extends AbstractJavaJAXRSServerCodegen im
@Override
public void postProcessModelProperty(CodegenModel model, CodegenProperty property) {
super.postProcessModelProperty(model, property);
//Add imports for Jackson
if (!BooleanUtils.toBoolean(model.isEnum)) {
model.imports.add("JsonProperty");

View File

@@ -234,6 +234,7 @@ public class JavascriptClientCodegen extends DefaultCodegen implements CodegenCo
if (StringUtils.isEmpty(System.getenv("JS_POST_PROCESS_FILE"))) {
LOGGER.info("Environment variable JS_POST_PROCESS_FILE not defined so the JS code may not be properly formatted. To define it, try 'export JS_POST_PROCESS_FILE=\"/usr/local/bin/js-beautify -r -f\"' (Linux/Mac)");
LOGGER.info("NOTE: To enable file post-processing, 'enablePostProcessFile' must be set to `true` (--enable-post-process-file for CLI).");
}
if (additionalProperties.containsKey(PROJECT_NAME)) {
@@ -296,7 +297,11 @@ public class JavascriptClientCodegen extends DefaultCodegen implements CodegenCo
}
if (projectDescription == null) {
// when projectDescription is not specified, use info.description
projectDescription = sanitizeName(info.getDescription());
if (StringUtils.isEmpty(info.getDescription())) {
projectDescription = "JS API client generated by OpenAPI Generator";
} else {
projectDescription = sanitizeName(info.getDescription());
}
}
// when licenceName is not specified, use info.license
@@ -505,13 +510,18 @@ public class JavascriptClientCodegen extends DefaultCodegen implements CodegenCo
private String getNameUsingModelPropertyNaming(String name) {
switch (CodegenConstants.MODEL_PROPERTY_NAMING_TYPE.valueOf(getModelPropertyNaming())) {
case original: return name;
case camelCase: return org.openapitools.codegen.utils.StringUtils.camelize(name, true);
case PascalCase: return org.openapitools.codegen.utils.StringUtils.camelize(name);
case snake_case: return org.openapitools.codegen.utils.StringUtils.underscore(name);
default: throw new IllegalArgumentException("Invalid model property naming '" +
name + "'. Must be 'original', 'camelCase', " +
"'PascalCase' or 'snake_case'");
case original:
return name;
case camelCase:
return org.openapitools.codegen.utils.StringUtils.camelize(name, true);
case PascalCase:
return org.openapitools.codegen.utils.StringUtils.camelize(name);
case snake_case:
return org.openapitools.codegen.utils.StringUtils.underscore(name);
default:
throw new IllegalArgumentException("Invalid model property naming '" +
name + "'. Must be 'original', 'camelCase', " +
"'PascalCase' or 'snake_case'");
}
}
@@ -870,7 +880,7 @@ public class JavascriptClientCodegen extends DefaultCodegen implements CodegenCo
codegenModel.getVendorExtensions().put("x-itemType", getSchemaType(ModelUtils.getAdditionalProperties(model)));
} else {
String type = model.getType();
if (isPrimitiveType(type)){
if (isPrimitiveType(type)) {
codegenModel.vendorExtensions.put("x-isPrimitive", true);
}
}

View File

@@ -31,9 +31,11 @@ import java.util.Map;
public class KotlinClientCodegen extends AbstractKotlinCodegen {
public static final String DATE_LIBRARY = "dateLibrary";
public static final String COLLECTION_TYPE = "collectionType";
private static final Logger LOGGER = LoggerFactory.getLogger(KotlinClientCodegen.class);
protected String dateLibrary = DateLibrary.JAVA8.value;
protected String collectionType = CollectionType.ARRAY.value;
public enum DateLibrary {
STRING("string"),
@@ -47,6 +49,17 @@ public class KotlinClientCodegen extends AbstractKotlinCodegen {
}
}
public enum CollectionType {
ARRAY("array"),
LIST("list");
public final String value;
CollectionType(String value) {
this.value = value;
}
}
/**
* Constructs an instance of `KotlinClientCodegen`.
*/
@@ -74,6 +87,13 @@ public class KotlinClientCodegen extends AbstractKotlinCodegen {
dateOptions.put(DateLibrary.JAVA8.value, "Java 8 native JSR310");
dateLibrary.setEnum(dateOptions);
cliOptions.add(dateLibrary);
CliOption collectionType = new CliOption(COLLECTION_TYPE, "Option. Collection type to use");
Map<String, String> collectionOptions = new HashMap<>();
collectionOptions.put(CollectionType.ARRAY.value, "kotlin.Array");
collectionOptions.put(CollectionType.LIST.value, "kotlin.collections.List");
collectionType.setEnum(collectionOptions);
cliOptions.add(collectionType);
}
public CodegenType getTag() {
@@ -92,6 +112,10 @@ public class KotlinClientCodegen extends AbstractKotlinCodegen {
this.dateLibrary = library;
}
public void setCollectionType(String collectionType) {
this.collectionType = collectionType;
}
@Override
public void processOpts() {
super.processOpts();
@@ -116,6 +140,15 @@ public class KotlinClientCodegen extends AbstractKotlinCodegen {
additionalProperties.put(DateLibrary.JAVA8.value, true);
}
if (additionalProperties.containsKey(COLLECTION_TYPE)) {
setCollectionType(additionalProperties.get(COLLECTION_TYPE).toString());
}
if (CollectionType.LIST.value.equals(collectionType)) {
typeMapping.put("array", "kotlin.collections.List");
typeMapping.put("list", "kotlin.collections.List");
}
supportingFiles.add(new SupportingFile("README.mustache", "", "README.md"));
supportingFiles.add(new SupportingFile("build.gradle.mustache", "", "build.gradle"));
supportingFiles.add(new SupportingFile("settings.gradle.mustache", "", "settings.gradle"));

View File

@@ -135,6 +135,7 @@ public class PerlClientCodegen extends DefaultCodegen implements CodegenConfig {
if (StringUtils.isEmpty(System.getenv("PERL_POST_PROCESS_FILE"))) {
LOGGER.info("Environment variable PERL_POST_PROCESS_FILE not defined so the Perl code may not be properly formatted. To define it, try 'export PERL_POST_PROCESS_FILE=/usr/local/bin/perltidy -b -bext=\"/\"' (Linux/Mac)");
LOGGER.info("NOTE: To enable file post-processing, 'enablePostProcessFile' must be set to `true` (--enable-post-process-file for CLI).");
}
if (additionalProperties.containsKey(MODULE_VERSION)) {

View File

@@ -424,6 +424,10 @@ public class PhpSymfonyServerCodegen extends AbstractPhpCodegen implements Codeg
var.vendorExtensions.put("x-parameterType", typeHint);
}
if (var.isContainer) {
var.vendorExtensions.put("x-parameterType", getTypeHint(var.dataType + "[]"));
}
// Create a variable to display the correct data type in comments for models
var.vendorExtensions.put("x-commentType", var.dataType);
if (var.isContainer) {

View File

@@ -174,6 +174,7 @@ public class PythonClientCodegen extends DefaultCodegen implements CodegenConfig
if (StringUtils.isEmpty(System.getenv("PYTHON_POST_PROCESS_FILE"))) {
LOGGER.info("Environment variable PYTHON_POST_PROCESS_FILE not defined so the Python code may not be properly formatted. To define it, try 'export PYTHON_POST_PROCESS_FILE=\"/usr/local/bin/yapf -i\"' (Linux/Mac)");
LOGGER.info("NOTE: To enable file post-processing, 'enablePostProcessFile' must be set to `true` (--enable-post-process-file for CLI).");
}
Boolean excludeTests = false;

View File

@@ -157,6 +157,7 @@ public class PythonFlaskConnexionServerCodegen extends DefaultCodegen implements
if (StringUtils.isEmpty(System.getenv("PYTHON_POST_PROCESS_FILE"))) {
LOGGER.info("Environment variable PYTHON_POST_PROCESS_FILE not defined so the Python code may not be properly formatted. To define it, try 'export PYTHON_POST_PROCESS_FILE=\"/usr/local/bin/yapf -i\"' (Linux/Mac)");
LOGGER.info("NOTE: To enable file post-processing, 'enablePostProcessFile' must be set to `true` (--enable-post-process-file for CLI).");
}
//apiTemplateFiles.clear();

View File

@@ -18,6 +18,8 @@
package org.openapitools.codegen.languages;
import io.swagger.v3.oas.models.media.Schema;
import io.swagger.v3.oas.models.parameters.Parameter;
import io.swagger.v3.oas.models.examples.Example;
import org.apache.commons.lang3.StringUtils;
import org.openapitools.codegen.*;
import org.slf4j.Logger;
@@ -536,6 +538,34 @@ public class RubyClientCodegen extends AbstractRubyCodegen {
p.example = example;
}
/**
* Return the example value of the parameter. Overrides the
* setParameterExampleValue(CodegenParameter, Parameter) method in
* DefaultCodegen to always call setParameterExampleValue(CodegenParameter)
* in this class, which adds single quotes around strings from the
* x-example property.
*
* @param codegenParameter Codegen parameter
* @param parameter Parameter
*/
public void setParameterExampleValue(CodegenParameter codegenParameter, Parameter parameter) {
if (parameter.getExample() != null) {
codegenParameter.example = parameter.getExample().toString();
} else if (parameter.getExamples() != null && !parameter.getExamples().isEmpty()) {
Example example = parameter.getExamples().values().iterator().next();
if (example.getValue() != null) {
codegenParameter.example = example.getValue().toString();
}
} else {
Schema schema = parameter.getSchema();
if (schema != null && schema.getExample() != null) {
codegenParameter.example = schema.getExample().toString();
}
}
setParameterExampleValue(codegenParameter);
}
public void setGemName(String gemName) {
this.gemName = gemName;
}

View File

@@ -20,6 +20,7 @@ package org.openapitools.codegen.languages;
import com.google.common.base.Strings;
import io.swagger.v3.oas.models.media.ArraySchema;
import io.swagger.v3.oas.models.media.Schema;
import io.swagger.v3.oas.models.media.StringSchema;
import org.openapitools.codegen.*;
import org.openapitools.codegen.utils.ModelUtils;
import org.openapitools.codegen.utils.StringUtils;
@@ -310,9 +311,17 @@ public class RustClientCodegen extends DefaultCodegen implements CodegenConfig {
if (ModelUtils.isArraySchema(p)) {
ArraySchema ap = (ArraySchema) p;
Schema inner = ap.getItems();
if (inner == null) {
LOGGER.warn(ap.getName() + "(array property) does not have a proper inner type defined.Default to string");
inner = new StringSchema().description("TODO default missing array inner type to string");
}
return "Vec<" + getTypeDeclaration(inner) + ">";
} else if (ModelUtils.isMapSchema(p)) {
Schema inner = ModelUtils.getAdditionalProperties(p);
if (inner == null) {
LOGGER.warn(p.getName() + "(map property) does not have a proper inner type defined. Default to string");
inner = new StringSchema().description("TODO default missing map inner type to string");
}
return "::std::collections::HashMap<String, " + getTypeDeclaration(inner) + ">";
}

View File

@@ -177,8 +177,7 @@ public class RustServerCodegen extends DefaultCodegen implements CodegenConfig {
"Rust crate name (convention: snake_case).")
.defaultValue("openapi_client"));
cliOptions.add(new CliOption(CodegenConstants.PACKAGE_VERSION,
"Rust crate version.")
.defaultValue("1.0.0"));
"Rust crate version."));
/*
* Additional Properties. These values can be passed to the templates and
@@ -224,8 +223,6 @@ public class RustServerCodegen extends DefaultCodegen implements CodegenConfig {
if (additionalProperties.containsKey(CodegenConstants.PACKAGE_VERSION)) {
setPackageVersion((String) additionalProperties.get(CodegenConstants.PACKAGE_VERSION));
} else {
setPackageVersion("1.0.0");
}
additionalProperties.put(CodegenConstants.PACKAGE_NAME, packageName);
@@ -477,6 +474,10 @@ public class RustServerCodegen extends DefaultCodegen implements CodegenConfig {
return mimetype.toLowerCase(Locale.ROOT).startsWith("text/plain");
}
boolean isMimetypeHtmlText(String mimetype) {
return mimetype.toLowerCase(Locale.ROOT).startsWith("text/html");
}
boolean isMimetypeWwwFormUrlEncoded(String mimetype) {
return mimetype.toLowerCase(Locale.ROOT).startsWith("application/x-www-form-urlencoded");
}
@@ -547,6 +548,8 @@ public class RustServerCodegen extends DefaultCodegen implements CodegenConfig {
consumesXml = true;
} else if (isMimetypePlainText(mimeType)) {
consumesPlainText = true;
} else if (isMimetypeHtmlText(mimeType)) {
consumesPlainText = true;
} else if (isMimetypeWwwFormUrlEncoded(mimeType)) {
additionalProperties.put("usesUrlEncodedForm", true);
}
@@ -573,6 +576,8 @@ public class RustServerCodegen extends DefaultCodegen implements CodegenConfig {
producesXml = true;
} else if (isMimetypePlainText(mimeType)) {
producesPlainText = true;
} else if (isMimetypeHtmlText(mimeType)) {
producesPlainText = true;
}
mediaType.put("mediaType", mimeType);
@@ -665,7 +670,7 @@ public class RustServerCodegen extends DefaultCodegen implements CodegenConfig {
if (isMimetypeXml(mediaType)) {
additionalProperties.put("usesXml", true);
consumesXml = true;
} else if (isMimetypePlainText(mediaType)) {
} else if (isMimetypePlainText(mediaType) || isMimetypeHtmlText(mediaType)) {
consumesPlainText = true;
} else if (isMimetypeWwwFormUrlEncoded(mediaType)) {
additionalProperties.put("usesUrlEncodedForm", true);

View File

@@ -239,6 +239,11 @@ public class ScalaGatlingCodegen extends AbstractScalaCodegen implements Codegen
continue;
}
for (Operation operation : path.readOperations()) {
if (operation.getExtensions() == null) {
operation.setExtensions(new HashMap());
}
if (!operation.getExtensions().keySet().contains("x-gatling-path")) {
if (pathname.contains("{")) {
String gatlingPath = pathname.replaceAll("\\{", "\\$\\{");

View File

@@ -77,6 +77,7 @@ public class SpringCodegen extends AbstractJavaCodegen
public static final String OPENAPI_DOCKET_CONFIG = "swaggerDocketConfig";
public static final String API_FIRST = "apiFirst";
public static final String HATEOAS = "hateoas";
public static final String RETURN_SUCCESS_CODE = "returnSuccessCode";
protected String title = "OpenAPI Spring";
protected String configPackage = "org.openapitools.configuration";
@@ -98,6 +99,7 @@ public class SpringCodegen extends AbstractJavaCodegen
protected boolean useOptional = false;
protected boolean virtualService = false;
protected boolean hateoas = false;
protected boolean returnSuccessCode = false;
public SpringCodegen() {
super();
@@ -131,6 +133,7 @@ public class SpringCodegen extends AbstractJavaCodegen
cliOptions.add(CliOption.newBoolean(API_FIRST, "Generate the API from the OAI spec at server compile time (API first approach)", apiFirst));
cliOptions.add(CliOption.newBoolean(USE_OPTIONAL,"Use Optional container for optional parameters", useOptional));
cliOptions.add(CliOption.newBoolean(HATEOAS, "Use Spring HATEOAS library to allow adding HATEOAS links", hateoas));
cliOptions.add(CliOption.newBoolean(RETURN_SUCCESS_CODE, "Generated server returns 2xx code", returnSuccessCode));
supportedLibraries.put(SPRING_BOOT, "Spring-boot Server application using the SpringFox integration.");
supportedLibraries.put(SPRING_MVC_LIBRARY, "Spring-MVC Server application using the SpringFox integration.");
@@ -277,6 +280,10 @@ public class SpringCodegen extends AbstractJavaCodegen
this.setHateoas(Boolean.valueOf(additionalProperties.get(HATEOAS).toString()));
}
if (additionalProperties.containsKey(RETURN_SUCCESS_CODE)) {
this.setReturnSuccessCode(Boolean.valueOf(additionalProperties.get(RETURN_SUCCESS_CODE).toString()));
}
typeMapping.put("file", "Resource");
importMapping.put("Resource", "org.springframework.core.io.Resource");
@@ -721,6 +728,10 @@ public class SpringCodegen extends AbstractJavaCodegen
this.hateoas = hateoas;
}
public void setReturnSuccessCode(boolean returnSuccessCode) {
this.returnSuccessCode = returnSuccessCode;
}
@Override
public void postProcessModelProperty(CodegenModel model, CodegenProperty property) {
super.postProcessModelProperty(model, property);

View File

@@ -245,6 +245,7 @@ public class Swift3Codegen extends DefaultCodegen implements CodegenConfig {
if (StringUtils.isEmpty(System.getenv("SWIFT_POST_PROCESS_FILE"))) {
LOGGER.info("Environment variable SWIFT_POST_PROCESS_FILE not defined so the Swift code may not be properly formatted. To define it, try 'export SWIFT_POST_PROCESS_FILE=/usr/local/bin/swiftformat' (Linux/Mac)");
LOGGER.info("NOTE: To enable file post-processing, 'enablePostProcessFile' must be set to `true` (--enable-post-process-file for CLI).");
}
// Setup project name

View File

@@ -300,6 +300,7 @@ public class Swift4Codegen extends DefaultCodegen implements CodegenConfig {
if (StringUtils.isEmpty(System.getenv("SWIFT_POST_PROCESS_FILE"))) {
LOGGER.info("Environment variable SWIFT_POST_PROCESS_FILE not defined so the Swift code may not be properly formatted. To define it, try 'export SWIFT_POST_PROCESS_FILE=/usr/local/bin/swiftformat' (Linux/Mac)");
LOGGER.info("NOTE: To enable file post-processing, 'enablePostProcessFile' must be set to `true` (--enable-post-process-file for CLI).");
}
// Setup project name

View File

@@ -472,7 +472,7 @@ public class TypeScriptAngularClientCodegen extends AbstractTypeScriptClientCode
@Override
public String toModelFilename(String name) {
return this.sanitizeName(this.convertUsingFileNamingConvention(name) + modelFileSuffix);
return this.convertUsingFileNamingConvention(this.sanitizeName(name) + modelFileSuffix);
}
@Override

View File

@@ -302,9 +302,13 @@ public class ModelUtils {
if (schema instanceof ObjectSchema) {
return true;
}
// must not be a map
if (SchemaTypeUtil.OBJECT_TYPE.equals(schema.getType()) && !(schema instanceof MapSchema)) {
return true;
}
// must have at least one property
if (schema.getType() == null && schema.getProperties() != null && !schema.getProperties().isEmpty()) {
return true;
}
@@ -501,7 +505,70 @@ public class ModelUtils {
}
/**
* If a Schema contains a reference to an other Schema with '$ref', returns the referenced Schema if it is found or the actual Schema in the other cases.
* Check to see if the schema is a model with at least one properties
*
* @param schema potentially containing a '$ref'
* @return true if it's a model with at least one properties
*/
public static boolean isModel(Schema schema) {
if (schema == null) {
LOGGER.error("Schema cannot be null in isModel check");
return false;
}
// has at least one property
if (schema.getProperties() != null && !schema.getProperties().isEmpty()) {
return true;
}
// composed schema is a model
if (schema instanceof ComposedSchema) {
return true;
}
return false;
}
/**
* Check to see if the schema is a free form object
*
* @param schema potentially containing a '$ref'
* @return true if it's a free-form object
*/
public static boolean isFreeFormObject(Schema schema) {
if (schema == null) {
LOGGER.error("Schema cannot be null in isFreeFormObject check");
return false;
}
// has at least one property
if ("object".equals(schema.getType())) {
// no properties
if ((schema.getProperties() == null || schema.getProperties().isEmpty())) {
if (schema.getAdditionalProperties() == null) {
return true;
} else {
// additionalProperties set to true
if (schema.getAdditionalProperties() instanceof Boolean
&& (Boolean) schema.getAdditionalProperties()) {
return true;
}
// additionalProperties is set to {}
if (schema.getAdditionalProperties() instanceof Schema && schema.getAdditionalProperties() != null
&& schema.getAdditionalProperties() instanceof ObjectSchema
&& ((Schema) schema.getAdditionalProperties()).getProperties().isEmpty()) {
return true;
}
}
}
}
return false;
}
/**
* If a Schema contains a reference to another Schema with '$ref', returns the referenced Schema if it is found or the actual Schema in the other cases.
*
* @param openAPI specification being checked
* @param schema potentially containing a '$ref'
@@ -623,7 +690,7 @@ public class ModelUtils {
/**
* If a Callback contains a reference to an other Callback with '$ref', returns the referenced Callback if it is found or the actual Callback in the other cases.
*
* @param openAPI specification being checked
* @param openAPI specification being checked
* @param callback potentially containing a '$ref'
* @return callback without '$ref'
*/
@@ -642,7 +709,7 @@ public class ModelUtils {
if (name == null) {
return null;
}
if (openAPI != null && openAPI.getComponents() != null && openAPI.getComponents().getCallbacks() != null) {
return openAPI.getComponents().getCallbacks().get(name);
}
@@ -689,7 +756,8 @@ public class ModelUtils {
*/
public static Schema unaliasSchema(Map<String, Schema> allSchemas, Schema schema) {
if (allSchemas == null || allSchemas.isEmpty()) {
LOGGER.warn("allSchemas cann't be null/empty in unaliasSchema. Returned 'schema'");
// skip the warning as the spec can have no model defined
//LOGGER.warn("allSchemas cannot be null/empty in unaliasSchema. Returned 'schema'");
return schema;
}
@@ -701,22 +769,17 @@ public class ModelUtils {
} else if (ref.getEnum() != null && !ref.getEnum().isEmpty()) {
// top-level enum class
return schema;
} else if (isArraySchema(ref) || isComposedSchema(ref)) { // array def should be created as models
} else if (isFreeFormObject(ref)) {
return schema;
} else if (isArraySchema(ref)) {
return unaliasSchema(allSchemas, allSchemas.get(ModelUtils.getSimpleRef(schema.get$ref())));
} else if (isComposedSchema(ref)) {
return schema;
} else if (isMapSchema(ref)) {
if (ref.getProperties() != null && !ref.getProperties().isEmpty()) // has properties
return schema; // treat it as model
else {
// treat it as a typical map
/* TODO unalias the map item if it's an alias
if (ref.getAdditionalProperties() != null) {
Schema innerSchema = (Schema) ref.getAdditionalProperties();
if (StringUtils.isNotEmpty(innerSchema.get$ref())) { // map item is a ref to something else
//Schema unaliasInnerSchema = unaliasSchema(allSchemas, allSchemas.get(ModelUtils.getSimpleRef(innerSchema.get$ref())));
//ref.setAdditionalProperties(unaliasInnerSchema);
}
}*/
return unaliasSchema(allSchemas, allSchemas.get(ModelUtils.getSimpleRef(schema.get$ref())));
}
} else if (isObjectSchema(ref)) { // model

View File

@@ -179,7 +179,7 @@ public class URLPathUtils {
LOGGER.warn("'scheme' not defined in the spec (2.0). Default to [http] for server URL [{}]", url);
} else if (url.startsWith("/")) {
url = LOCAL_HOST + url;
LOGGER.warn("'host' not defined in the spec (2.0). Default to [{}] for server URL [{}]", LOCAL_HOST, url);
LOGGER.warn("'host' (OAS 2.0) or 'servers' (OAS 3.0) not defined in the spec. Default to [{}] for server URL [{}]", LOCAL_HOST, url);
} else if (!url.matches("[a-zA-Z][0-9a-zA-Z.+\\-]+://.+")) {
// Add http scheme for urls without a scheme.
// 2.0 spec is restricted to the following schemes: "http", "https", "ws", "wss"

View File

@@ -0,0 +1,94 @@
cmake_minimum_required (VERSION 2.6)
project (CGenerator)
file(GLOB SRC_C src/*.c)
#file(GLOB UNIT_TESTS_C unit-tests/*.c)
#file(GLOB UNIT_TEST_C unit-test/*.c)
file(GLOB MODEL_C model/*.c)
file(GLOB API_C api/*.c)
file(GLOB EXTERNAL_SRC_C external/src/*.c)
set(ALL_SRC_LIST ${SRC_C} ${UNIT_TESTS_C} ${UNIT_TEST_C} ${MODEL_C} ${API_C})
set(CMAKE_BUILD_TYPE Debug)
include(CTest)
include_directories(include)
include_directories(external/include)
include_directories(model)
include_directories(api)
find_program(VALGRIND valgrind)
if(VALGRIND)
set(CMAKE_MEMORYCHECK_COMMAND valgrind)
set(CMAKE_MEMORYCHECK_COMMAND_OPTIONS "--leak-check=full --track-origins=yes --read-var-info=yes --show-leak-kinds=all --error-exitcode=1")
set(VALGRIND_LIST "")
endif()
find_package(CURL 7.61.1 REQUIRED)
if(CURL_FOUND)
include_directories(${CURL_INCLUDE_DIR})
set(PLATFORM_LIBRARIES ${PLATFORM_LIBRARIES} ${CURL_LIBRARIES} )
else(CURL_FOUND)
message(FATAL_ERROR "Could not find the CURL library and development files.")
endif()
# comment out below as auto-generated test file is not supported at the moment
#foreach(ELEMENT ${UNIT_TESTS_C})
# get_filename_component(ELEMENT_NAME ${ELEMENT} NAME_WE)
# string(REGEX REPLACE "\\.c$" "" ELEMENT_REPLACED ${ELEMENT_NAME})
# set(EXE_NAME unit-${ELEMENT_REPLACED})
# add_executable(${EXE_NAME} ${ELEMENT} ${SRC_C} ${MODEL_C} ${API_C} ${EXTERNAL_SRC_C})
# target_link_libraries(${EXE_NAME} ${CURL_LIBRARIES})
# add_test(NAME ${EXE_NAME} COMMAND ${CMAKE_CURRENT_BINARY_DIR}/${EXE_NAME})
#
# if(VALGRIND)
# set(memcheck_command "${CMAKE_MEMORYCHECK_COMMAND} ${CMAKE_MEMORYCHECK_COMMAND_OPTIONS}")
# separate_arguments(memcheck_command)
#
# add_test(
# NAME valgrind-test-${ELEMENT_REPLACED}
# COMMAND ${memcheck_command} ${CMAKE_CURRENT_BINARY_DIR}/${EXE_NAME}
# WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
# )
# endif()
#endforeach()
#
#foreach(ELEMENT ${UNIT_TEST_C})
#get_filename_component(ELEMENT_NAME ${ELEMENT} NAME_WE)
#string(REGEX REPLACE "\\.c$" "" ELEMENT_REPLACED ${ELEMENT_NAME})
#set(EXE_NAME unit-${ELEMENT_REPLACED})
#add_executable(${EXE_NAME} ${ELEMENT} ${SRC_C} ${MODEL_C} ${API_C} ${EXTERNAL_SRC_C})
#target_link_libraries(${EXE_NAME} ${CURL_LIBRARIES})
#add_test(NAME ${EXE_NAME} COMMAND ${CMAKE_CURRENT_BINARY_DIR}/${EXE_NAME})
#
#if(VALGRIND)
#set(memcheck_command "${CMAKE_MEMORYCHECK_COMMAND} ${CMAKE_MEMORYCHECK_COMMAND_OPTIONS}")
#separate_arguments(memcheck_command)
#
#add_test(
#NAME valgrind-test-${ELEMENT_REPLACED}
#COMMAND ${memcheck_command} ${CMAKE_CURRENT_BINARY_DIR}/${EXE_NAME}
#WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
#)
#endif()
#endforeach()
#For common coding standard (code beautifier/pretty printing)
find_program(UNCRUSTIFY uncrustify)
if(UNCRUSTIFY)
add_custom_target(
uncrustify
)
foreach(ELEMENT ${ALL_SRC_LIST})
string(REGEX REPLACE "/" "_" ELEMENT_NAME ${ELEMENT})
set(DEP_NAME "uncrustify-${ELEMENT_NAME}")
add_custom_target(
${DEP_NAME}
uncrustify -c uncrustify-rules.cfg --no-backup ${ELEMENT}
DEPENDS ${ELEMENT}
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
VERBATIM
)
add_dependencies(uncrustify ${DEP_NAME})
endforeach()
endif()

View File

@@ -0,0 +1,45 @@
# C API client for {{{projectName}}}
## Overview
This API client was generated by the [OpenAPI Generator](https://openapi-generator.tech) project. By using the [OpenAPI spec](https://openapis.org) from a remote server, you can easily generate an API client.
- API version: {{appVersion}}
- Package version: {{packageVersion}}
{{^hideGenerationTimestamp}}
- Build date: {{generatedDate}}
{{/hideGenerationTimestamp}}
- Build package: {{generatorClass}}
{{#infoUrl}}
For more information, please visit [{{{infoUrl}}}]({{{infoUrl}}})
{{/infoUrl}}
## Installation
You'll need the `curl 7.61.1` package in order to build the API. To have code formatted nicely you also need to have uncrustify version 0.67.
### Prerequisites
Install the `curl 7.61.1` package with the following command on Linux.
```bash
sudo apt remove curl
wget http://curl.haxx.se/download/curl-7.61.1.tar.gz
tar -xvf curl-7.61.1.tar.gz
cd curl-7.61.1/
./configure
make
sudo make install
```
Install the `uncrustify 0.67` package with the following command on Linux.
```bash
git clone https://github.com/uncrustify/uncrustify.git
cd uncrustify
mkdir build
cd build
cmake ..
make
sudo make install
```
## Author
{{#apiInfo}}{{#apis}}{{^hasMore}}{{infoEmail}}
{{/hasMore}}{{/apis}}{{/apiInfo}}

View File

@@ -0,0 +1,454 @@
#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>
#include "apiClient.h"
#include "cJSON.h"
#include "keyValuePair.h"
{{#imports}}{{{import}}}
{{/imports}}
#define MAX_BUFFER_LENGTH 4096
#define intToStr(dst, src) \
do {\
char dst[256];\
snprintf(dst, 256, "%ld", (long int)(src));\
}while(0)
{{#operations}}
{{#operation}}
{{#summary}}
// {{{summary}}}
//
{{/summary}}
{{#notes}}
// {{{notes}}}
//
{{/notes}}
{{#returnType}}{{#returnTypeIsPrimitive}}{{#returnSimpleType}}{{{.}}}*{{/returnSimpleType}}{{^returnSimpleType}}{{{.}}}{{/returnSimpleType}}{{/returnTypeIsPrimitive}}{{^returnTypeIsPrimitive}}{{{.}}}_t*{{/returnTypeIsPrimitive}}{{/returnType}}{{^returnType}}void{{/returnType}}
{{{classname}}}_{{{operationId}}}(apiClient_t *apiClient{{#allParams}}, {{{dataType}}}{{#isPrimitiveType}}{{#isString}}*{{/isString}}{{#isFile}}*{{/isFile}}{{/isPrimitiveType}}{{^isPrimitiveType}}_t*{{/isPrimitiveType}} {{{paramName}}}{{/allParams}}) {
list_t *localVarQueryParameters = {{#hasQueryParams}}list_create();{{/hasQueryParams}}{{^hasQueryParams}}NULL;{{/hasQueryParams}}
list_t *localVarHeaderParameters = {{#hasHeaderParams}}list_create();{{/hasHeaderParams}}{{^hasHeaderParams}}NULL;{{/hasHeaderParams}}
list_t *localVarFormParameters = {{#hasFormParams}}list_create();{{/hasFormParams}}{{^hasFormParams}}NULL;{{/hasFormParams}}
list_t *localVarHeaderType = {{#hasProduces}}list_create();{{/hasProduces}}{{^hasProduces}}NULL;{{/hasProduces}}
list_t *localVarContentType = {{#hasConsumes}}list_create();{{/hasConsumes}}{{^hasConsumes}}NULL;{{/hasConsumes}}
char *localVarBodyParameters = NULL;
// create the path
long sizeOfPath = strlen("{{{path}}}")+1;
char *localVarPath = malloc(sizeOfPath);
snprintf(localVarPath, sizeOfPath, "{{{path}}}");
{{#pathParams}}
// Path Params
long sizeOfPathParams_{{{paramName}}} = {{#pathParams}}{{#isLong}}sizeof({{paramName}})+3{{/isLong}}{{#isString}}strlen({{paramName}})+3{{/isString}}{{/pathParams}} + strlen("{ {{paramName}} }");
{{#isLong}}
if({{paramName}} == 0){
goto end;
}
char* localVarToReplace_{{paramName}} = malloc(sizeOfPathParams_{{paramName}});
snprintf(localVarToReplace_{{paramName}}, sizeOfPathParams_{{paramName}}, "%s%s%s", "{", "{{paramName}}", "}");
char localVarBuff_{{paramName}}[256];
intToStr(localVarBuff_{{paramName}}, {{paramName}});
localVarPath = strReplace(localVarPath, localVarToReplace_{{paramName}}, localVarBuff_{{paramName}});
{{/isLong}}
{{#isString}}
if({{paramName}} == NULL) {
goto end;
}
char* localVarToReplace_{{paramName}} = malloc(sizeOfPathParams_{{paramName}});
sprintf(localVarToReplace_{{paramName}}, "%s%s%s", "{", "{{paramName}}", "}");
localVarPath = strReplace(localVarPath, localVarToReplace_{{paramName}}, {{paramName}});
{{/isString}}
{{/pathParams}}
{{#headerParams}}
{{#isString}}
// header parameters
char *keyHeader_{{{paramName}}};
char *valueHeader_{{{paramName}}};
keyValuePair_t *keyPairHeader_{{paramName}} = 0;
if ({{paramName}}) {
keyHeader_{{{paramName}}} = strdup("{{{paramName}}}");
valueHeader_{{{paramName}}} = strdup({{{paramName}}});
keyPairHeader_{{paramName}} = keyValuePair_create(keyHeader_{{{paramName}}}, valueHeader_{{{paramName}}});
list_addElement(localVarHeaderParameters,keyPairHeader_{{paramName}});
}
{{/isString}}
{{^isString}}
// header parameters
char *keyHeader_{{{paramName}}};
{{dataType}} valueHeader_{{{paramName}}};
keyValuePair_t *keyPairHeader_{{paramName}} = 0;
if ({{paramName}}) {
keyHeader_{{{paramName}}} = strdup("{{{paramName}}}");
valueHeader_{{{paramName}}} = {{{paramName}}};
keyPairHeader_{{paramName}} = keyValuePair_create(keyHeader_{{{paramName}}}, &valueHeader_{{{paramName}}});
list_addElement(localVarHeaderParameters,keyPairHeader_{{paramName}});
}
{{/isString}}
{{/headerParams}}
{{#queryParams}}
// query parameters
{{#isListContainer}}
if ({{paramName}})
{{/isListContainer}}
{{^isListContainer}}
{{#isString}}
char *keyQuery_{{{paramName}}};
char *valueQuery_{{{paramName}}};
keyValuePair_t *keyPairQuery_{{paramName}} = 0;
if ({{paramName}})
{{/isString}}
{{^isString}}
char *keyQuery_{{{paramName}}};
{{dataType}} valueQuery_{{{paramName}}};
keyValuePair_t *keyPairQuery_{{paramName}} = 0;
if ({{paramName}})
{{/isString}}
{{/isListContainer}}
{
{{#isListContainer}}
//listContainer
localVarQueryParameters = {{{paramName}}};
{{/isListContainer}}
{{^isListContainer}}
{{#isString}}
//string
keyQuery_{{{paramName}}} = strdup("{{{paramName}}}");
valueQuery_{{{paramName}}} = strdup({{{paramName}}});
keyPairQuery_{{paramName}} = keyValuePair_create(keyQuery_{{{paramName}}}, valueQuery_{{{paramName}}});
list_addElement(localVarQueryParameters,keyPairQuery_{{paramName}});
{{/isString}}
{{^isString}}
//not string
keyQuery_{{{paramName}}} = strdup("{{{paramName}}}");
valueQuery_{{{paramName}}} = {{{paramName}}};
keyPairQuery_{{paramName}} = keyValuePair_create(keyQuery_{{{paramName}}}, &valueQuery_{{{paramName}}});
list_addElement(localVarQueryParameters,keyPairQuery_{{paramName}});
{{/isString}}
{{/isListContainer}}
}
{{/queryParams}}
{{#formParams}}
// form parameters
{{#isFile}}
char *keyForm_{{paramName}};
FileStruct *fileVar_{{paramName}};
keyValuePair_t *keyPairForm_{{paramName}} = 0;
if ({{paramName}} != NULL)
{{/isFile}}
{{^isFile}}
{{#isString}}
char *keyForm_{{paramName}};
char *valueForm_{{paramName}};
keyValuePair_t *keyPairForm_{{paramName}} = 0;
if ({{paramName}})
{{/isString}}
{{^isString}}
char *keyForm_{{paramName}};
{{dataType}} valueForm_{{paramName}};
keyValuePair_t *keyPairForm_{{paramName}} = 0;
if ({{paramName}})
{{/isString}}
{{/isFile}}
{
{{#isFile}}
fseek({{paramName}}, 0, SEEK_END);
long f_size = ftell({{paramName}});
fseek({{paramName}}, 0, SEEK_SET);
fileVar_{{paramName}} = malloc(sizeof(FileStruct));
keyForm_{{paramName}} = strdup("{{{paramName}}}");
fileVar_{{paramName}}->fileData = malloc((f_size)* sizeof(char*));
fread(fileVar_{{paramName}}->fileData, f_size, 1, file);
fileVar_{{paramName}}->fileData[f_size] = '\0';
fileVar_{{paramName}}->fileSize = f_size;
char valueFile_{{paramName}}[sizeof(fileVar_{{paramName}})];
memcpy(valueFile_{{paramName}},&fileVar_{{paramName}}, sizeof(fileVar_{{paramName}}));
keyPairForm_{{paramName}} = keyValuePair_create(keyForm_{{paramName}},valueFile_{{paramName}});
list_addElement(localVarFormParameters,keyPairForm_{{paramName}}); //file adding
{{/isFile}}
{{^isFile}}
{{#isString}}
keyForm_{{paramName}} = strdup("{{{paramName}}}");
valueForm_{{paramName}} = strdup({{paramName}});
keyPairForm_{{paramName}} = keyValuePair_create(keyForm_{{paramName}},valueForm_{{paramName}});
list_addElement(localVarFormParameters,keyPairForm_{{paramName}}); //String
{{/isString}}
{{^isString}}
keyForm_{{paramName}} = strdup("{{{paramName}}}");
valueForm_{{paramName}} = {{paramName}};
keyPairForm_{{paramName}} = keyValuePair_create(keyForm_{{paramName}},&valueForm_{{paramName}});
list_addElement(localVarFormParameters,keyPairForm_{{paramName}}); // not String
{{/isString}}
{{/isFile}}
}
{{/formParams}}
{{#bodyParam}}
// Body Param
{{#isListContainer}}
//notstring
cJSON *localVar_{{paramName}};
cJSON *localVarItemJSON_{{paramName}};
cJSON *localVarSingleItemJSON_{{paramName}};
if ({{paramName}} != NULL) {
localVarItemJSON_{{paramName}} = cJSON_CreateObject();
localVarSingleItemJSON_{{paramName}} = cJSON_AddArrayToObject(localVarItemJSON_{{paramName}}, "{{paramName}}");
if (localVarSingleItemJSON_{{paramName}} == NULL) {
// nonprimitive container
const char *error_ptr = cJSON_GetErrorPtr();
if(error_ptr != NULL) {
fprintf(stderr, "Error Before: %s\n", error_ptr);
goto end;
}
}
listEntry_t *{{paramName}}BodyListEntry;
list_ForEach({{paramName}}BodyListEntry, {{paramName}}) {
localVar_{{paramName}} = {{paramName}}_convertToJSON({{paramName}}BodyListEntry->data);
if(localVar_{{paramName}} == NULL) {
const char *error_ptr = cJSON_GetErrorPtr();
if(error_ptr != NULL) {
fprintf(stderr, "Error Before: %s\n", error_ptr);
goto end;
}
}
cJSON_AddItemToArray(localVarSingleItemJSON_{{paramName}}, localVar_{{paramName}});
}
localVarBodyParameters = cJSON_Print(localVarItemJSON_{{paramName}});
}
{{/isListContainer}}
{{^isListContainer}}
cJSON *localVarSingleItemJSON_{{paramName}};
if ({{paramName}} != NULL) {
//string
localVarSingleItemJSON_{{paramName}} = {{paramName}}_convertToJSON({{paramName}});
localVarBodyParameters = cJSON_Print(localVarSingleItemJSON_{{paramName}});
}
{{/isListContainer}}
{{/bodyParam}}
{{#produces}}
list_addElement(localVarHeaderType,"{{{mediaType}}}"); //produces
{{/produces}}
{{#consumes}}
list_addElement(localVarContentType,"{{{mediaType}}}"); //consumes
{{/consumes}}
apiClient_invoke(apiClient,
localVarPath,
localVarQueryParameters,
localVarHeaderParameters,
localVarFormParameters,
localVarHeaderType,
localVarContentType,
localVarBodyParameters,
"{{{httpMethod}}}");
{{#responses}}
if (apiClient->response_code == {{code}}) {
printf("%s\n","{{message}}");
}
{{/responses}}
{{#returnType}}
{{#returnTypeIsPrimitive}}
{{#returnSimpleType}}
//primitive reutrn type simple
{{returnType}}* elementToReturn = strdup(({{returnType}}*)apiClient->dataReceived);
{{/returnSimpleType}}
{{^returnSimpleType}}
//primitive reutrn type not simple
cJSON *{{paramName}}localVarJSON = cJSON_Parse(apiClient->dataReceived);
cJSON *{{{paramName}}}VarJSON;
list_t *elementToReturn = list_create();
cJSON_ArrayForEach({{{paramName}}}VarJSON, {{paramName}}localVarJSON){
keyValuePair_t *keyPair = keyValuePair_create(strdup({{{paramName}}}VarJSON->string), cJSON_Print({{{paramName}}}VarJSON));
list_addElement(elementToReturn, keyPair);
}
cJSON_Delete({{paramName}}localVarJSON);
{{/returnSimpleType}}
{{/returnTypeIsPrimitive}}
{{^returnTypeIsPrimitive}}
{{#returnContainer}}
cJSON *{{classname}}localVarJSON = cJSON_Parse(apiClient->dataReceived);
if(!cJSON_IsArray({{classname}}localVarJSON)) {
return 0;//nonprimitive container
}
list_t *elementToReturn = list_create();
cJSON *{{{paramName}}}VarJSON;
cJSON_ArrayForEach({{{paramName}}}VarJSON, {{classname}}localVarJSON)
{
if(!cJSON_IsObject({{{paramName}}}VarJSON))
{
// return 0;
}
char *localVarJSONToChar = cJSON_Print({{{paramName}}}VarJSON);
list_addElement(elementToReturn , localVarJSONToChar);
}
cJSON_Delete( {{classname}}localVarJSON);
cJSON_Delete( {{{paramName}}}VarJSON);
{{/returnContainer}}
{{^returnContainer}}
//nonprimitive not container
{{{returnBaseType}}}_t *elementToReturn = {{{returnBaseType}}}_parseFromJSON(apiClient->dataReceived);
if(elementToReturn == NULL) {
// return 0;
}
{{/returnContainer}}
//return type
{{/returnTypeIsPrimitive}}
apiClient_free(apiClient);
{{#hasQueryParams}}list_free(localVarQueryParameters);{{/hasQueryParams}}
{{#hasHeaderParams}}list_free(localVarHeaderParameters);{{/hasHeaderParams}}
{{#hasFormParams}}list_free(localVarFormParameters);{{/hasFormParams}}
{{#hasProduces}}list_free(localVarHeaderType);{{/hasProduces}}
{{#hasConsumes}}list_free(localVarContentType);{{/hasConsumes}}
free(localVarPath);
{{#pathParams}}
free(localVarToReplace_{{paramName}});
{{/pathParams}}
{{#headerParams}}
{{#isString}}
free(keyHeader_{{{paramName}}});
free(valueHeader_{{{paramName}}});
{{/isString}}
{{^isString}}
free(keyHeader_{{{paramName}}});
{{/isString}}
free(keyPairHeader_{{paramName}});
{{/headerParams}}
{{#bodyParams}}
{{#isListContainer}}
cJSON_Delete(localVarItemJSON_{{paramName}});
cJSON_Delete(localVarSingleItemJSON_{{paramName}});
cJSON_Delete(localVar_{{paramName}});
free(localVarBodyParameters);
{{/isListContainer}}
{{^isListContainer}}
cJSON_Delete(localVarSingleItemJSON_{{paramName}});
free(localVarBodyParameters);
{{/isListContainer}}
{{/bodyParams}}
{{#queryParams}}
{{^isListContainer}}
{{#isString}}
free(keyQuery_{{{paramName}}});
free(valueQuery_{{{paramName}}});
keyValuePair_free(keyPairQuery_{{{paramName}}});
{{/isString}}
{{^isString}}
free(keyQuery_{{{paramName}}});
keyValuePair_free(keyPairQuery_{{{paramName}}});
{{/isString}}
{{/isListContainer}}
{{/queryParams}}
{{#formParams}}
{{#isFile}}
free(keyForm_{{{paramName}}});
free(fileVar_{{paramName}}->fileData);
free(fileVar_{{paramName}});
free(keyPairForm_{{paramName}});
{{/isFile}}
{{^isFile}}
{{#isString}}
free(keyForm_{{{paramName}}});
free(valueForm_{{{paramName}}});
free(keyPairForm_{{paramName}});
{{/isString}}
{{^isString}}
free(keyForm_{{{paramName}}});
free(keyPairForm_{{paramName}});
{{/isString}}
{{/isFile}}
{{/formParams}}
return elementToReturn;
end:
return NULL;
{{/returnType}}
{{^returnType}}
//No return type
end: apiClient_free(apiClient);
{{#hasQueryParams}}list_free(localVarQueryParameters);{{/hasQueryParams}}
{{#hasHeaderParams}}list_free(localVarHeaderParameters);{{/hasHeaderParams}}
{{#hasFormParams}}list_free(localVarFormParameters);{{/hasFormParams}}
{{#hasProduces}}list_free(localVarHeaderType);{{/hasProduces}}
{{#hasConsumes}}list_free(localVarContentType);{{/hasConsumes}}
free(localVarPath);
{{#pathParams}}
free(localVarToReplace_{{paramName}});
{{/pathParams}}
{{#headerParams}}
{{#isString}}
free(keyHeader_{{{paramName}}});
free(valueHeader_{{{paramName}}});
{{/isString}}
{{^isString}}
free(keyHeader_{{{paramName}}});
{{/isString}}
free(keyPairHeader_{{paramName}});
{{/headerParams}}
{{#bodyParams}}
{{#isListContainer}}
cJSON_Delete(localVarItemJSON_{{paramName}});
cJSON_Delete(localVarSingleItemJSON_{{paramName}});
cJSON_Delete(localVar_{{paramName}});
free(localVarBodyParameters);
{{/isListContainer}}
{{^isListContainer}}
cJSON_Delete(localVarSingleItemJSON_{{paramName}});
free(localVarBodyParameters);
{{/isListContainer}}
{{/bodyParams}}
{{#queryParams}}
{{^isListContainer}}
{{#isString}}
free(keyQuery_{{{paramName}}});
free(valueQuery_{{{paramName}}});
keyValuePair_free(keyPairQuery_{{{paramName}}});
{{/isString}}
{{#isString}}
free(keyQuery_{{{paramName}}});
keyValuePair_free(keyPairQuery_{{{paramName}}});
{{/isString}}
{{/isListContainer}}
{{/queryParams}}
{{#formParams}}
{{#isFile}}
free(keyForm_{{{paramName}}});
free(fileVar_{{paramName}}->fileData);
free(fileVar_{{paramName}});
{{/isFile}}
{{^isFile}}
{{#isString}}
free(keyForm_{{{paramName}}});
free(valueForm_{{{paramName}}});
keyValuePair_free(keyPairForm_{{{paramName}}});
{{/isString}}
{{^isString}}
free(keyForm_{{{paramName}}});
free(keyPairForm_{{paramName}});
{{/isString}}
{{/isFile}}
{{/formParams}}
{{/returnType}}
}
{{/operation}}
{{/operations}}

View File

@@ -0,0 +1,25 @@
#include <stdlib.h>
#include <stdio.h>
#include "apiClient.h"
#include "cJSON.h"
{{#imports}}{{{import}}}
{{/imports}}
{{#operations}}
{{#operation}}
{{#summary}}
// {{{summary}}}
//
{{/summary}}
{{#notes}}
// {{{notes}}}
//
{{/notes}}
{{#returnType}}{{#returnTypeIsPrimitive}}{{#returnSimpleType}}{{{.}}}*{{/returnSimpleType}}{{^returnSimpleType}}{{{.}}}{{/returnSimpleType}}{{/returnTypeIsPrimitive}}{{^returnTypeIsPrimitive}}{{{.}}}_t*{{/returnTypeIsPrimitive}}{{/returnType}}{{^returnType}}void{{/returnType}}
{{{classname}}}_{{{operationId}}}(apiClient_t *apiClient{{#allParams}},{{{dataType}}}{{#isPrimitiveType}}{{#isString}}*{{/isString}}{{#isFile}}*{{/isFile}}{{/isPrimitiveType}}{{^isPrimitiveType}}_t*{{/isPrimitiveType}} {{{paramName}}} {{/allParams}});
{{/operation}}
{{/operations}}

View File

@@ -0,0 +1,449 @@
#include <curl/curl.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include "apiClient.h"
#include "keyValuePair.h"
size_t writeDataCallback(void *buffer, size_t size, size_t nmemb, void *userp);
apiClient_t *apiClient_create() {
curl_global_init(CURL_GLOBAL_ALL);
apiClient_t *apiClient = malloc(sizeof(apiClient_t));
apiClient->basePath = "{{{basePath}}}";
apiClient->dataReceived = NULL;
apiClient->response_code = 0;
#ifdef BASIC_AUTH
apiClient->username = NULL;
apiClient->password = NULL;
#endif // BASIC_AUTH
#ifdef OAUTH2
apiClient->accessToken = NULL;
#endif // OAUTH2
return apiClient;
}
void apiClient_free(apiClient_t *apiClient) {
if(apiClient->dataReceived) {
free(apiClient->dataReceived);
}
free(apiClient);
curl_global_cleanup();
}
void replaceSpaceWithPlus(char *stringToProcess) {
for(int i = 0; i < strlen(stringToProcess); i++) {
if(stringToProcess[i] == ' ') {
stringToProcess[i] = '+';
}
}
}
char *assembleTargetUrl(char *basePath,
char *operationParameter,
list_t *queryParameters) {
int neededBufferSizeForQueryParameters = 0;
listEntry_t *listEntry;
if(queryParameters != NULL) {
list_ForEach(listEntry, queryParameters) {
keyValuePair_t *pair = listEntry->data;
neededBufferSizeForQueryParameters +=
strlen(pair->key) + strlen(pair->value);
}
neededBufferSizeForQueryParameters +=
(queryParameters->count * 2); // each keyValuePair is separated by a = and a & except the last, but this makes up for the ? at the beginning
}
int operationParameterLength = 0;
int basePathLength = strlen(basePath);
bool slashNeedsToBeAppendedToBasePath = false;
if(operationParameter != NULL) {
operationParameterLength = (1 + strlen(operationParameter));
}
if(basePath[strlen(basePath) - 1] != '/') {
slashNeedsToBeAppendedToBasePath = true;
basePathLength++;
}
char *targetUrl =
malloc(
neededBufferSizeForQueryParameters + basePathLength + operationParameterLength +
1);
strcpy(targetUrl, basePath);
if(operationParameter != NULL) {
strcat(targetUrl, operationParameter);
}
if(queryParameters != NULL) {
strcat(targetUrl, "?");
list_ForEach(listEntry, queryParameters) {
keyValuePair_t *pair = listEntry->data;
replaceSpaceWithPlus(pair->key);
strcat(targetUrl, pair->key);
strcat(targetUrl, "=");
replaceSpaceWithPlus(pair->value);
strcat(targetUrl, pair->value);
if(listEntry->nextListEntry != NULL) {
strcat(targetUrl, "&");
}
}
}
return targetUrl;
}
char *assembleHeaderField(char *key, char *value) {
char *header = malloc(strlen(key) + strlen(value) + 3);
strcpy(header, key),
strcat(header, ": ");
strcat(header, value);
return header;
}
void postData(CURL *handle, char *bodyParameters) {
curl_easy_setopt(handle, CURLOPT_POSTFIELDS, bodyParameters);
curl_easy_setopt(handle, CURLOPT_POSTFIELDSIZE_LARGE,
strlen(bodyParameters));
}
int lengthOfKeyPair(keyValuePair_t *keyPair) {
long length = 0;
if((keyPair->key != NULL) &&
(keyPair->value != NULL) )
{
length = strlen(keyPair->key) + strlen(keyPair->value);
return length;
}
return 0;
}
void apiClient_invoke(apiClient_t *apiClient,
char *operationParameter,
list_t *queryParameters,
list_t *headerParameters,
list_t *formParameters,
list_t *headerType,
list_t *contentType,
char *bodyParameters,
char *requestType) {
CURL *handle = curl_easy_init();
CURLcode res;
if(handle) {
listEntry_t *listEntry;
curl_mime *mime = NULL;
struct curl_slist *headers = NULL;
char *buffContent = NULL;
char *buffHeader = NULL;
FileStruct *fileVar = NULL;
char *formString = NULL;
if(headerType != NULL) {
list_ForEach(listEntry, headerType) {
if(strstr((char *) listEntry->data,
"xml") == NULL)
{
buffHeader = malloc(strlen(
"Accept: ") +
strlen((char *)
listEntry->
data) + 1);
sprintf(buffHeader, "%s%s", "Accept: ",
(char *) listEntry->data);
headers = curl_slist_append(headers,
buffHeader);
free(buffHeader);
}
}
}
if(contentType != NULL) {
list_ForEach(listEntry, contentType) {
if(strstr((char *) listEntry->data,
"xml") == NULL)
{
buffContent =
malloc(strlen(
"Content-Type: ") + strlen(
(char *)
listEntry->data) +
1);
sprintf(buffContent, "%s%s",
"Content-Type: ",
(char *) listEntry->data);
headers = curl_slist_append(headers,
buffContent);
}
}
} else {
headers = curl_slist_append(headers,
"Content-Type: application/json");
}
if(requestType != NULL) {
curl_easy_setopt(handle, CURLOPT_CUSTOMREQUEST,
requestType);
}
if(formParameters != NULL) {
if(strstr(buffContent,
"application/x-www-form-urlencoded") != NULL)
{
long parameterLength = 0;
long keyPairLength = 0;
list_ForEach(listEntry, formParameters) {
keyValuePair_t *keyPair =
listEntry->data;
keyPairLength =
lengthOfKeyPair(keyPair) + 1;
if(listEntry->nextListEntry != NULL) {
parameterLength++;
}
parameterLength = parameterLength +
keyPairLength;
}
formString = malloc(parameterLength + 1);
memset(formString, 0, parameterLength + 1);
list_ForEach(listEntry, formParameters) {
keyValuePair_t *keyPair =
listEntry->data;
if((keyPair->key != NULL) &&
(keyPair->value != NULL) )
{
strcat(formString,
keyPair->key);
strcat(formString, "=");
strcat(formString,
keyPair->value);
if(listEntry->nextListEntry !=
NULL)
{
strcat(formString, "&");
}
}
}
curl_easy_setopt(handle, CURLOPT_POSTFIELDS,
formString);
}
if(strstr(buffContent, "multipart/form-data") != NULL) {
mime = curl_mime_init(handle);
list_ForEach(listEntry, formParameters) {
keyValuePair_t *keyValuePair =
listEntry->data;
if((keyValuePair->key != NULL) &&
(keyValuePair->value != NULL) )
{
curl_mimepart *part =
curl_mime_addpart(mime);
curl_mime_name(part,
keyValuePair->key);
if(strcmp(keyValuePair->key,
"file") == 0)
{
printf("Size of fileVar - %p\n",fileVar);
memcpy(&fileVar,
keyValuePair->value,
sizeof(fileVar));
printf("Size of fileVar1 - %p\n",fileVar);
curl_mime_data(part,
fileVar->fileData,
fileVar->fileSize);
curl_mime_filename(part,
"image.png");
} else {
curl_mime_data(part,
keyValuePair->value,
CURL_ZERO_TERMINATED);
}
}
}
curl_easy_setopt(handle, CURLOPT_MIMEPOST,
mime);
}
}
list_ForEach(listEntry, headerParameters) {
keyValuePair_t *keyValuePair = listEntry->data;
if((keyValuePair->key != NULL) &&
(keyValuePair->value != NULL) )
{
char *headerValueToWrite = assembleHeaderField(
keyValuePair->key, keyValuePair->value);
curl_slist_append(headers, headerValueToWrite);
free(headerValueToWrite);
}
}
// this would only be generated for apiKey authentication
#ifdef API_KEY
list_ForEach(listEntry, apiClient->apiKeys) {
keyValuePair_t *apiKey = listEntry->data;
if((apiKey->key != NULL) &&
(apiKey->value != NULL) )
{
char *headerValueToWrite = assembleHeaderField(
apiKey->key, apiKey->value);
curl_slist_append(headers, headerValueToWrite);
free(headerValueToWrite);
}
}
#endif // API_KEY
char *targetUrl =
assembleTargetUrl(apiClient->basePath,
operationParameter,
queryParameters);
curl_easy_setopt(handle, CURLOPT_URL, targetUrl);
curl_easy_setopt(handle,
CURLOPT_WRITEFUNCTION,
writeDataCallback);
curl_easy_setopt(handle,
CURLOPT_WRITEDATA,
&apiClient->dataReceived);
curl_easy_setopt(handle, CURLOPT_HTTPHEADER, headers);
curl_easy_setopt(handle, CURLOPT_VERBOSE, 0); // to get curl debug msg 0: to disable, 1L:to enable
// this would only be generated for OAuth2 authentication
#ifdef OAUTH2
if(apiClient->accessToken != NULL) {
// curl_easy_setopt(handle, CURLOPT_HTTPAUTH, CURLAUTH_BEARER);
curl_easy_setopt(handle,
CURLOPT_XOAUTH2_BEARER,
apiClient->accessToken);
}
#endif
// this would only be generated for basic authentication:
#ifdef BASIC_AUTH
char *authenticationToken;
if((apiClient->username != NULL) &&
(apiClient->password != NULL) )
{
authenticationToken = malloc(strlen(
apiClient->username) +
strlen(
apiClient->password) +
2);
sprintf(authenticationToken,
"%s:%s",
apiClient->username,
apiClient->password);
curl_easy_setopt(handle,
CURLOPT_HTTPAUTH,
CURLAUTH_BASIC);
curl_easy_setopt(handle,
CURLOPT_USERPWD,
authenticationToken);
}
#endif // BASIC_AUTH
if(bodyParameters != NULL) {
postData(handle, bodyParameters);
}
res = curl_easy_perform(handle);
curl_slist_free_all(headers);
free(targetUrl);
if(contentType != NULL) {
free(buffContent);
}
if(res == CURLE_OK) {
curl_easy_getinfo(handle, CURLINFO_RESPONSE_CODE, &apiClient->response_code);
} else {
fprintf(stderr, "curl_easy_perform() failed: %s\n",
curl_easy_strerror(res));
}
#ifdef BASIC_AUTH
if((apiClient->username != NULL) &&
(apiClient->password != NULL) )
{
free(authenticationToken);
}
#endif // BASIC_AUTH
curl_easy_cleanup(handle);
if(formParameters != NULL) {
free(formString);
curl_mime_free(mime);
}
}
}
size_t writeDataCallback(void *buffer, size_t size, size_t nmemb, void *userp) {
*(char **) userp = strdup(buffer);
return size * nmemb;
}
char *strReplace(char *orig, char *rep, char *with) {
char *result; // the return string
char *ins; // the next insert point
char *tmp; // varies
int lenRep; // length of rep (the string to remove)
int lenWith; // length of with (the string to replace rep with)
int lenFront; // distance between rep and end of last rep
int count; // number of replacements
// sanity checks and initialization
if(!orig || !rep)
{
return NULL;
}
lenRep = strlen(rep);
if(lenRep == 0) {
return NULL; // empty rep causes infinite loop during count
}
if(!with) {
with = "";
}
lenWith = strlen(with);
// count the number of replacements needed
ins = orig;
for(count = 0; tmp = strstr(ins, rep); ++count) {
ins = tmp + lenRep;
}
tmp = result = malloc(strlen(orig) + (lenWith - lenRep) * count + 1);
if(!result) {
return NULL;
}
char *originalPointer = orig; // copying original pointer to free the memory
// first time through the loop, all the variable are set correctly
// from here on,
// tmp points to the end of the result string
// ins points to the next occurrence of rep in orig
// orig points to the remainder of orig after "end of rep"
while(count--) {
ins = strstr(orig, rep);
lenFront = ins - orig;
tmp = strncpy(tmp, orig, lenFront) + lenFront;
tmp = strcpy(tmp, with) + lenWith;
orig += lenFront + lenRep; // move to next "end of rep"
}
strcpy(tmp, orig);
free(originalPointer);
return result;
}

View File

@@ -0,0 +1,43 @@
#ifndef INCLUDE_API_CLIENT_H
#define INCLUDE_API_CLIENT_H
#include "list.h"
typedef int bool;
#define true 1
#define false 0
typedef struct apiClient_t {
char *basePath;
void *dataReceived;
long response_code;
// this would only be generated for basic authentication
#ifdef BASIC_AUTH
char *username;
char *password;
#endif // BASIC_AUTH
// this would only be generated for OAUTH2 authentication
#ifdef OAUTH2
char *accessToken;
#endif // OAUTH2
#ifdef API_KEY
//this would only be generated for apiKey authentication
list_t *apiKeys;
#endif // API_KEY
} apiClient_t;
typedef struct FileStruct
{
char* fileData;
long fileSize;
}FileStruct;
apiClient_t* apiClient_create();
void apiClient_free(apiClient_t *apiClient);
void apiClient_invoke(apiClient_t *apiClient,char* operationParameter, list_t *queryParameters, list_t *headerParameters, list_t *formParameters,list_t *headerType,list_t *contentType, char *bodyParameters, char *requestType);
char *strReplace(char *orig, char *rep, char *with);
#endif // INCLUDE_API_CLIENT_H

View File

@@ -0,0 +1,14 @@
#include <stdlib.h>
#include <string.h>
#include "keyValuePair.h"
keyValuePair_t *keyValuePair_create(char *key, void *value) {
keyValuePair_t *keyValuePair = malloc(sizeof(keyValuePair_t));
keyValuePair->key = key;
keyValuePair->value = value;
return keyValuePair;
}
void keyValuePair_free(keyValuePair_t *keyValuePair) {
free(keyValuePair);
}

View File

@@ -0,0 +1,128 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include "apiClient.h"
#include "cJSON.h"
#include "pet.h"
#include "PetAPI.h"
#include "category.h"
#include "tag.h"
#include "keyValuePair.h"
#define EXAMPLE_CATEGORY_NAME "Example Category"
#define EXAMPLE_CATEGORY_ID 5
#define EXAMPLE_PET_NAME "Example Pet"
#define EXAMPLE_URL_1 "http://www.github.com"
#define EXAMPLE_URL_2 "http://www.gitter.im"
#define EXAMPLE_TAG_1_NAME "beautiful code"
#define EXAMPLE_TAG_2_NAME "at least I tried"
#define EXAMPLE_TAG_1_ID 1
#define EXAMPLE_TAG_2_ID 542353
#define EXAMPLE_PET_ID 1234 // Set to 0 to generate a new pet
int main() {
// Add pet test
apiClient_t *apiClient = apiClient_create();
char *categoryName = malloc(strlen(EXAMPLE_CATEGORY_NAME) + 1);
strcpy(categoryName, EXAMPLE_CATEGORY_NAME);
category_t *category =
category_create(EXAMPLE_CATEGORY_ID, categoryName);
char *petName = malloc(strlen(EXAMPLE_PET_NAME) + 1);
strcpy(petName, EXAMPLE_PET_NAME);
char *exampleUrl1 = malloc(strlen(EXAMPLE_URL_1) + 1);
strcpy(exampleUrl1, EXAMPLE_URL_1);
char *exampleUrl2 = malloc(strlen(EXAMPLE_URL_2) + 1);
strcpy(exampleUrl2, EXAMPLE_URL_2);
list_t *photoUrls = list_create();
list_addElement(photoUrls, exampleUrl1);
list_addElement(photoUrls, exampleUrl2);
char *exampleTag1Name = malloc(strlen(EXAMPLE_TAG_1_NAME) + 1);
strcpy(exampleTag1Name, EXAMPLE_TAG_1_NAME);
tag_t *exampleTag1 = tag_create(EXAMPLE_TAG_1_ID, exampleTag1Name);
char *exampleTag2Name = malloc(strlen(EXAMPLE_TAG_2_NAME) + 1);
strcpy(exampleTag2Name, EXAMPLE_TAG_2_NAME);
tag_t *exampleTag2 = tag_create(EXAMPLE_TAG_2_ID, exampleTag2Name);
list_t *tags = list_create();
list_addElement(tags, exampleTag1);
list_addElement(tags, exampleTag2);
status_e status = available;
pet_t *pet =
pet_create(EXAMPLE_PET_ID,
category,
petName,
photoUrls,
tags,
status);
PetAPI_addPet(apiClient, pet);
pet_free(pet);
//Pet update with form test
char *petName1 = "Rocky Handsome";
char *petName2 = "sold";
apiClient_t *apiClient1 = apiClient_create();
PetAPI_updatePetWithForm(apiClient1, EXAMPLE_PET_ID, petName1,
petName2);
//Get pet by id test
apiClient_t *apiClient2 = apiClient_create();
pet_t *mypet = PetAPI_getPetById(apiClient2, EXAMPLE_PET_ID);
cJSON *JSONR = pet_convertToJSON(mypet);
char *petJson = cJSON_Print(JSONR);
printf("Data is:%s\n", petJson);
assert(strcmp(mypet->name, "Rocky Handsome") == 0);
assert(mypet->id == EXAMPLE_PET_ID);
assert(strcmp(mypet->category->name, EXAMPLE_CATEGORY_NAME) == 0);
assert(mypet->category->id == EXAMPLE_CATEGORY_ID);
assert(strcmp(list_getElementAt(mypet->photoUrls,
0)->data, EXAMPLE_URL_1) == 0);
assert(strcmp(list_getElementAt(mypet->photoUrls,
1)->data, EXAMPLE_URL_2) == 0);
assert(((tag_t *) list_getElementAt(mypet->tags,
0)->data)->id == EXAMPLE_TAG_1_ID);
assert(((tag_t *) list_getElementAt(mypet->tags,
1)->data)->id == EXAMPLE_TAG_2_ID);
assert(strcmp(((tag_t *) list_getElementAt(mypet->tags, 0)->data)->name,
EXAMPLE_TAG_1_NAME) == 0);
assert(strcmp(((tag_t *) list_getElementAt(mypet->tags, 1)->data)->name,
EXAMPLE_TAG_2_NAME) == 0);
free(petJson);
cJSON_Delete(JSONR);
pet_free(mypet);
//Pet upload file Test
apiClient_t *apiClient3 = apiClient_create();
FILE *file = fopen("/opt/image.png", "r");
if(file != NULL){
api_response_t *respo = PetAPI_uploadFile(apiClient3,
EXAMPLE_PET_ID,
"dec",
file);
api_response_free(respo);
fclose(file);
}
}

View File

@@ -0,0 +1,94 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include "apiClient.h"
#include "cJSON.h"
#include "order.h"
#include "StoreAPI.h"
#include "keyValuePair.h"
#define ORDER_ID 1234
#define PET_ID 12345
#define QUANTITY 50
#define SHIP_DATE "2018-09-24T10:19:09.592Z"
#define STATUS placed
#define COMPLETE true
/*
Creates one pet and adds it. Then gets the pet with the just added ID and compare if the values are equal.
Could fail if someone else makes changes to the added pet, before it can be fetched again.
*/
int main() {
//place order test
apiClient_t *apiClient = apiClient_create();
char *shipdate = malloc(strlen(SHIP_DATE) + 1);
strcpy(shipdate, SHIP_DATE);
order_t *neworder = order_create(ORDER_ID,
PET_ID,
QUANTITY,
shipdate,
STATUS,
COMPLETE);
order_t *returnorder = StoreAPI_placeOrder(apiClient, neworder);
cJSON *JSONNODE = order_convertToJSON(returnorder);
char *dataToPrint = cJSON_Print(JSONNODE);
printf("Placed order: \n%s\n", dataToPrint);
order_free(neworder);
order_free(returnorder);
cJSON_Delete(JSONNODE);
free(dataToPrint);
//order get by id test
apiClient_t *apiClient2 = apiClient_create();
neworder = StoreAPI_getOrderById(apiClient2, 1234);
JSONNODE = order_convertToJSON(neworder);
char *dataToPrint1 = cJSON_Print(JSONNODE);
printf("Order received: \n%s\n", dataToPrint1);
order_free(neworder);
cJSON_Delete(JSONNODE);
free(dataToPrint1);
//delete order test
apiClient_t *apiClient3 = apiClient_create();
char *orderid = malloc(strlen("1234") + 1);
strcpy(orderid, "1234");
StoreAPI_deleteOrder(apiClient3, orderid);
printf("Order Deleted \n");
free(orderid);
// get order by id test
apiClient_t *apiClient4 = apiClient_create();
neworder = StoreAPI_getOrderById(apiClient4, 1234);
if(neworder == NULL) {
printf("Order Not present \n");
}
//get inventory test
apiClient_t *apiClient5 = apiClient_create();
list_t *elementToReturn;
elementToReturn = StoreAPI_getInventory(apiClient5);
listEntry_t *listEntry;
list_ForEach(listEntry, elementToReturn) {
keyValuePair_free(listEntry->data);
}
list_free(elementToReturn);
}

View File

@@ -0,0 +1,15 @@
#include <stdio.h>
#define MAX_BUFFER_LENGTH 9
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include "keyValuePair.h"
int main() {
printf("Hello world1\n");
}

View File

@@ -0,0 +1,121 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include "apiClient.h"
#include "cJSON.h"
#include "keyValuePair.h"
#include "user.h"
#include "UserAPI.h"
#define USER_ID 1234
#define USER_NAME "example123"
#define FIRST_NAME "Example1"
#define LAST_NAME "Example2Last"
#define LAST_NAME1 "LastName"
#define EMAIL "example@example.com"
#define PASSWORD "thisisexample!123"
#define PHONE "+123456789"
#define USER_STATUS 4
int main() {
//create user test
apiClient_t *apiClient = apiClient_create();
char *username = malloc(strlen(USER_NAME) + 1);
strcpy(username, USER_NAME);
char *firstname = malloc(strlen(FIRST_NAME) + 1);
strcpy(firstname, FIRST_NAME);
char *lastname = malloc(strlen(LAST_NAME) + 1);
strcpy(lastname, LAST_NAME);
char *email = malloc(strlen(EMAIL) + 1);
strcpy(email, EMAIL);
char *password = malloc(strlen(PASSWORD) + 1);
strcpy(password, PASSWORD);
char *phone = malloc(strlen(PHONE) + 1);
strcpy(phone, PHONE);
user_t *newuser = user_create(USER_ID,
username,
firstname,
lastname,
email,
password,
phone,
USER_STATUS);
UserAPI_createUser(apiClient, newuser);
user_free(newuser);
//get user by name test
apiClient_t *apiClient1 = apiClient_create();
user_t *returnUser = UserAPI_getUserByName(apiClient1, USER_NAME);
cJSON *JSONNODE = user_convertToJSON(returnUser);
char *dataToPrint = cJSON_Print(JSONNODE);
printf("User is: \n%s\n", dataToPrint);
user_free(returnUser);
cJSON_Delete(JSONNODE);
free(dataToPrint);
//update user test
{
apiClient_t *apiClient2 = apiClient_create();
char *username1 = malloc(strlen(USER_NAME) + 1);
strcpy(username1, USER_NAME);
char *firstname = malloc(strlen(FIRST_NAME) + 1);
strcpy(firstname, FIRST_NAME);
char *lastname = malloc(strlen(LAST_NAME) + 1);
strcpy(lastname, LAST_NAME);
char *email = malloc(strlen(EMAIL) + 1);
strcpy(email, EMAIL);
char *password = malloc(strlen(PASSWORD) + 1);
strcpy(password, PASSWORD);
char *phone = malloc(strlen(PHONE) + 1);
strcpy(phone, PHONE);
user_t *newuser1 = user_create(USER_ID,
username1,
firstname,
lastname,
email,
password,
phone,
USER_STATUS);
UserAPI_updateUser(apiClient2, username1, newuser1);
user_free(newuser1);
}
//login user test
{
char *username1 = malloc(strlen(USER_NAME) + 1);
strcpy(username1, USER_NAME);
char *password = malloc(strlen(PASSWORD) + 1);
strcpy(password, PASSWORD);
apiClient_t *apiClient3 = apiClient_create();
char *loginuserreturn = UserAPI_loginUser(apiClient3,
username1,
password);
printf("Login User: %s\n", loginuserreturn);
free(loginuserreturn);
free(username1);
free(password);
}
// logout user test
apiClient_t *apiClient4 = apiClient_create();
UserAPI_logoutUser(apiClient4);
// delete user test
apiClient_t *apiClient5 = apiClient_create();
UserAPI_deleteUser(apiClient5, "example123");
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,277 @@
/*
Copyright (c) 2009-2017 Dave Gamble and cJSON contributors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#ifndef cJSON__h
#define cJSON__h
#ifdef __cplusplus
extern "C"
{
#endif
/* project version */
#define CJSON_VERSION_MAJOR 1
#define CJSON_VERSION_MINOR 7
#define CJSON_VERSION_PATCH 7
#include <stddef.h>
/* cJSON Types: */
#define cJSON_Invalid (0)
#define cJSON_False (1 << 0)
#define cJSON_True (1 << 1)
#define cJSON_NULL (1 << 2)
#define cJSON_Number (1 << 3)
#define cJSON_String (1 << 4)
#define cJSON_Array (1 << 5)
#define cJSON_Object (1 << 6)
#define cJSON_Raw (1 << 7) /* raw json */
#define cJSON_IsReference 256
#define cJSON_StringIsConst 512
/* The cJSON structure: */
typedef struct cJSON
{
/* next/prev allow you to walk array/object chains. Alternatively, use GetArraySize/GetArrayItem/GetObjectItem */
struct cJSON *next;
struct cJSON *prev;
/* An array or object item will have a child pointer pointing to a chain of the items in the array/object. */
struct cJSON *child;
/* The type of the item, as above. */
int type;
/* The item's string, if type==cJSON_String and type == cJSON_Raw */
char *valuestring;
/* writing to valueint is DEPRECATED, use cJSON_SetNumberValue instead */
int valueint;
/* The item's number, if type==cJSON_Number */
double valuedouble;
/* The item's name string, if this item is the child of, or is in the list of subitems of an object. */
char *string;
} cJSON;
typedef struct cJSON_Hooks
{
void *(*malloc_fn)(size_t sz);
void (*free_fn)(void *ptr);
} cJSON_Hooks;
typedef int cJSON_bool;
#if !defined(__WINDOWS__) && (defined(WIN32) || defined(WIN64) || defined(_MSC_VER) || defined(_WIN32))
#define __WINDOWS__
#endif
#ifdef __WINDOWS__
/* When compiling for windows, we specify a specific calling convention to avoid issues where we are being called from a project with a different default calling convention. For windows you have 2 define options:
CJSON_HIDE_SYMBOLS - Define this in the case where you don't want to ever dllexport symbols
CJSON_EXPORT_SYMBOLS - Define this on library build when you want to dllexport symbols (default)
CJSON_IMPORT_SYMBOLS - Define this if you want to dllimport symbol
For *nix builds that support visibility attribute, you can define similar behavior by
setting default visibility to hidden by adding
-fvisibility=hidden (for gcc)
or
-xldscope=hidden (for sun cc)
to CFLAGS
then using the CJSON_API_VISIBILITY flag to "export" the same symbols the way CJSON_EXPORT_SYMBOLS does
*/
/* export symbols by default, this is necessary for copy pasting the C and header file */
#if !defined(CJSON_HIDE_SYMBOLS) && !defined(CJSON_IMPORT_SYMBOLS) && !defined(CJSON_EXPORT_SYMBOLS)
#define CJSON_EXPORT_SYMBOLS
#endif
#if defined(CJSON_HIDE_SYMBOLS)
#define CJSON_PUBLIC(type) type __stdcall
#elif defined(CJSON_EXPORT_SYMBOLS)
#define CJSON_PUBLIC(type) __declspec(dllexport) type __stdcall
#elif defined(CJSON_IMPORT_SYMBOLS)
#define CJSON_PUBLIC(type) __declspec(dllimport) type __stdcall
#endif
#else /* !WIN32 */
#if (defined(__GNUC__) || defined(__SUNPRO_CC) || defined (__SUNPRO_C)) && defined(CJSON_API_VISIBILITY)
#define CJSON_PUBLIC(type) __attribute__((visibility("default"))) type
#else
#define CJSON_PUBLIC(type) type
#endif
#endif
/* Limits how deeply nested arrays/objects can be before cJSON rejects to parse them.
* This is to prevent stack overflows. */
#ifndef CJSON_NESTING_LIMIT
#define CJSON_NESTING_LIMIT 1000
#endif
/* returns the version of cJSON as a string */
CJSON_PUBLIC(const char*) cJSON_Version(void);
/* Supply malloc, realloc and free functions to cJSON */
CJSON_PUBLIC(void) cJSON_InitHooks(cJSON_Hooks* hooks);
/* Memory Management: the caller is always responsible to free the results from all variants of cJSON_Parse (with cJSON_Delete) and cJSON_Print (with stdlib free, cJSON_Hooks.free_fn, or cJSON_free as appropriate). The exception is cJSON_PrintPreallocated, where the caller has full responsibility of the buffer. */
/* Supply a block of JSON, and this returns a cJSON object you can interrogate. */
CJSON_PUBLIC(cJSON *) cJSON_Parse(const char *value);
/* ParseWithOpts allows you to require (and check) that the JSON is null terminated, and to retrieve the pointer to the final byte parsed. */
/* If you supply a ptr in return_parse_end and parsing fails, then return_parse_end will contain a pointer to the error so will match cJSON_GetErrorPtr(). */
CJSON_PUBLIC(cJSON *) cJSON_ParseWithOpts(const char *value, const char **return_parse_end, cJSON_bool require_null_terminated);
/* Render a cJSON entity to text for transfer/storage. */
CJSON_PUBLIC(char *) cJSON_Print(const cJSON *item);
/* Render a cJSON entity to text for transfer/storage without any formatting. */
CJSON_PUBLIC(char *) cJSON_PrintUnformatted(const cJSON *item);
/* Render a cJSON entity to text using a buffered strategy. prebuffer is a guess at the final size. guessing well reduces reallocation. fmt=0 gives unformatted, =1 gives formatted */
CJSON_PUBLIC(char *) cJSON_PrintBuffered(const cJSON *item, int prebuffer, cJSON_bool fmt);
/* Render a cJSON entity to text using a buffer already allocated in memory with given length. Returns 1 on success and 0 on failure. */
/* NOTE: cJSON is not always 100% accurate in estimating how much memory it will use, so to be safe allocate 5 bytes more than you actually need */
CJSON_PUBLIC(cJSON_bool) cJSON_PrintPreallocated(cJSON *item, char *buffer, const int length, const cJSON_bool format);
/* Delete a cJSON entity and all subentities. */
CJSON_PUBLIC(void) cJSON_Delete(cJSON *c);
/* Returns the number of items in an array (or object). */
CJSON_PUBLIC(int) cJSON_GetArraySize(const cJSON *array);
/* Retrieve item number "index" from array "array". Returns NULL if unsuccessful. */
CJSON_PUBLIC(cJSON *) cJSON_GetArrayItem(const cJSON *array, int index);
/* Get item "string" from object. Case insensitive. */
CJSON_PUBLIC(cJSON *) cJSON_GetObjectItem(const cJSON * const object, const char * const string);
CJSON_PUBLIC(cJSON *) cJSON_GetObjectItemCaseSensitive(const cJSON * const object, const char * const string);
CJSON_PUBLIC(cJSON_bool) cJSON_HasObjectItem(const cJSON *object, const char *string);
/* For analysing failed parses. This returns a pointer to the parse error. You'll probably need to look a few chars back to make sense of it. Defined when cJSON_Parse() returns 0. 0 when cJSON_Parse() succeeds. */
CJSON_PUBLIC(const char *) cJSON_GetErrorPtr(void);
/* Check if the item is a string and return its valuestring */
CJSON_PUBLIC(char *) cJSON_GetStringValue(cJSON *item);
/* These functions check the type of an item */
CJSON_PUBLIC(cJSON_bool) cJSON_IsInvalid(const cJSON * const item);
CJSON_PUBLIC(cJSON_bool) cJSON_IsFalse(const cJSON * const item);
CJSON_PUBLIC(cJSON_bool) cJSON_IsTrue(const cJSON * const item);
CJSON_PUBLIC(cJSON_bool) cJSON_IsBool(const cJSON * const item);
CJSON_PUBLIC(cJSON_bool) cJSON_IsNull(const cJSON * const item);
CJSON_PUBLIC(cJSON_bool) cJSON_IsNumber(const cJSON * const item);
CJSON_PUBLIC(cJSON_bool) cJSON_IsString(const cJSON * const item);
CJSON_PUBLIC(cJSON_bool) cJSON_IsArray(const cJSON * const item);
CJSON_PUBLIC(cJSON_bool) cJSON_IsObject(const cJSON * const item);
CJSON_PUBLIC(cJSON_bool) cJSON_IsRaw(const cJSON * const item);
/* These calls create a cJSON item of the appropriate type. */
CJSON_PUBLIC(cJSON *) cJSON_CreateNull(void);
CJSON_PUBLIC(cJSON *) cJSON_CreateTrue(void);
CJSON_PUBLIC(cJSON *) cJSON_CreateFalse(void);
CJSON_PUBLIC(cJSON *) cJSON_CreateBool(cJSON_bool boolean);
CJSON_PUBLIC(cJSON *) cJSON_CreateNumber(double num);
CJSON_PUBLIC(cJSON *) cJSON_CreateString(const char *string);
/* raw json */
CJSON_PUBLIC(cJSON *) cJSON_CreateRaw(const char *raw);
CJSON_PUBLIC(cJSON *) cJSON_CreateArray(void);
CJSON_PUBLIC(cJSON *) cJSON_CreateObject(void);
/* Create a string where valuestring references a string so
* it will not be freed by cJSON_Delete */
CJSON_PUBLIC(cJSON *) cJSON_CreateStringReference(const char *string);
/* Create an object/arrray that only references it's elements so
* they will not be freed by cJSON_Delete */
CJSON_PUBLIC(cJSON *) cJSON_CreateObjectReference(const cJSON *child);
CJSON_PUBLIC(cJSON *) cJSON_CreateArrayReference(const cJSON *child);
/* These utilities create an Array of count items. */
CJSON_PUBLIC(cJSON *) cJSON_CreateIntArray(const int *numbers, int count);
CJSON_PUBLIC(cJSON *) cJSON_CreateFloatArray(const float *numbers, int count);
CJSON_PUBLIC(cJSON *) cJSON_CreateDoubleArray(const double *numbers, int count);
CJSON_PUBLIC(cJSON *) cJSON_CreateStringArray(const char **strings, int count);
/* Append item to the specified array/object. */
CJSON_PUBLIC(void) cJSON_AddItemToArray(cJSON *array, cJSON *item);
CJSON_PUBLIC(void) cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item);
/* Use this when string is definitely const (i.e. a literal, or as good as), and will definitely survive the cJSON object.
* WARNING: When this function was used, make sure to always check that (item->type & cJSON_StringIsConst) is zero before
* writing to `item->string` */
CJSON_PUBLIC(void) cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJSON *item);
/* Append reference to item to the specified array/object. Use this when you want to add an existing cJSON to a new cJSON, but don't want to corrupt your existing cJSON. */
CJSON_PUBLIC(void) cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item);
CJSON_PUBLIC(void) cJSON_AddItemReferenceToObject(cJSON *object, const char *string, cJSON *item);
/* Remove/Detatch items from Arrays/Objects. */
CJSON_PUBLIC(cJSON *) cJSON_DetachItemViaPointer(cJSON *parent, cJSON * const item);
CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromArray(cJSON *array, int which);
CJSON_PUBLIC(void) cJSON_DeleteItemFromArray(cJSON *array, int which);
CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObject(cJSON *object, const char *string);
CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObjectCaseSensitive(cJSON *object, const char *string);
CJSON_PUBLIC(void) cJSON_DeleteItemFromObject(cJSON *object, const char *string);
CJSON_PUBLIC(void) cJSON_DeleteItemFromObjectCaseSensitive(cJSON *object, const char *string);
/* Update array items. */
CJSON_PUBLIC(void) cJSON_InsertItemInArray(cJSON *array, int which, cJSON *newitem); /* Shifts pre-existing items to the right. */
CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemViaPointer(cJSON * const parent, cJSON * const item, cJSON * replacement);
CJSON_PUBLIC(void) cJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newitem);
CJSON_PUBLIC(void) cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem);
CJSON_PUBLIC(void) cJSON_ReplaceItemInObjectCaseSensitive(cJSON *object,const char *string,cJSON *newitem);
/* Duplicate a cJSON item */
CJSON_PUBLIC(cJSON *) cJSON_Duplicate(const cJSON *item, cJSON_bool recurse);
/* Duplicate will create a new, identical cJSON item to the one you pass, in new memory that will
need to be released. With recurse!=0, it will duplicate any children connected to the item.
The item->next and ->prev pointers are always zero on return from Duplicate. */
/* Recursively compare two cJSON items for equality. If either a or b is NULL or invalid, they will be considered unequal.
* case_sensitive determines if object keys are treated case sensitive (1) or case insensitive (0) */
CJSON_PUBLIC(cJSON_bool) cJSON_Compare(const cJSON * const a, const cJSON * const b, const cJSON_bool case_sensitive);
CJSON_PUBLIC(void) cJSON_Minify(char *json);
/* Helper functions for creating and adding items to an object at the same time.
* They return the added item or NULL on failure. */
CJSON_PUBLIC(cJSON*) cJSON_AddNullToObject(cJSON * const object, const char * const name);
CJSON_PUBLIC(cJSON*) cJSON_AddTrueToObject(cJSON * const object, const char * const name);
CJSON_PUBLIC(cJSON*) cJSON_AddFalseToObject(cJSON * const object, const char * const name);
CJSON_PUBLIC(cJSON*) cJSON_AddBoolToObject(cJSON * const object, const char * const name, const cJSON_bool boolean);
CJSON_PUBLIC(cJSON*) cJSON_AddNumberToObject(cJSON * const object, const char * const name, const double number);
CJSON_PUBLIC(cJSON*) cJSON_AddStringToObject(cJSON * const object, const char * const name, const char * const string);
CJSON_PUBLIC(cJSON*) cJSON_AddRawToObject(cJSON * const object, const char * const name, const char * const raw);
CJSON_PUBLIC(cJSON*) cJSON_AddObjectToObject(cJSON * const object, const char * const name);
CJSON_PUBLIC(cJSON*) cJSON_AddArrayToObject(cJSON * const object, const char * const name);
/* When assigning an integer value, it needs to be propagated to valuedouble too. */
#define cJSON_SetIntValue(object, number) ((object) ? (object)->valueint = (object)->valuedouble = (number) : (number))
/* helper for the cJSON_SetNumberValue macro */
CJSON_PUBLIC(double) cJSON_SetNumberHelper(cJSON *object, double number);
#define cJSON_SetNumberValue(object, number) ((object != NULL) ? cJSON_SetNumberHelper(object, (double)number) : (number))
/* Macro for iterating over an array or object */
#define cJSON_ArrayForEach(element, array) for(element = (array != NULL) ? (array)->child : NULL; element != NULL; element = element->next)
/* malloc/free objects using the malloc/free functions that have been set with cJSON_InitHooks */
CJSON_PUBLIC(void *) cJSON_malloc(size_t size);
CJSON_PUBLIC(void) cJSON_free(void *object);
#ifdef __cplusplus
}
#endif
#endif

Some files were not shown because too many files have changed in this diff Show More