gibahjoe / openapi-generator-dart

Openapi Generator for Dart/Flutter
BSD 3-Clause "New" or "Revised" License
128 stars 34 forks source link

Parsing nullable `num` values #141

Closed InAnadea closed 1 week ago

InAnadea commented 7 months ago

Description of the bug

Nullable num fields can't be parsed using parse constructor. It should use tryParse.

Steps to reproduce

"Place": {
        "type": "object",
        "title": "Place",
        "description": "Attributes describing a place. Not all attributes will be available for all place types.",
        "properties": {
          "address_components": {
            "description": "An array containing the separate components applicable to this address.",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AddressComponent"
            }
          },
          "adr_address": {
            "description": "A representation of the place's address in the [adr microformat](http://microformats.org/wiki/adr).",
            "type": "string",
            "example": "<span class=\"street-address\">48 Pirrama Rd</span>, <span class=\"locality\">Pyrmont</span> <span class=\"region\">NSW</span> <span class=\"postal-code\">2009</span>, <span class=\"country-name\">Australia</span>"
          },
          "business_status": {
            "description": "Indicates the operational status of the place, if it is a business. If no data exists, `business_status` is not returned.\n",
            "type": "string",
            "enum": [
              "OPERATIONAL",
              "CLOSED_TEMPORARILY",
              "CLOSED_PERMANENTLY"
            ]
          },
          "curbside_pickup": {
            "description": "Specifies if the business supports curbside pickup.",
            "type": "boolean"
          },
          "current_opening_hours": {
            "description": "Contains the hours of operation for the next seven days (including today). The time period starts at midnight on the date of the request and ends at 11:59 pm six days later. This field includes the `special_days` subfield of all hours, set for dates that have exceptional hours.",
            "$ref": "#/components/schemas/PlaceOpeningHours"
          },
          "delivery": {
            "description": "Specifies if the business supports delivery.",
            "type": "boolean"
          },
          "dine_in": {
            "description": "Specifies if the business supports indoor or outdoor seating options.",
            "type": "boolean"
          },
          "editorial_summary": {
            "description": "Contains a summary of the place. A summary is comprised of a textual overview, and also includes the language code for these if applicable. Summary text must be presented as-is and can not be modified or altered.",
            "$ref": "#/components/schemas/PlaceEditorialSummary"
          },
          "formatted_address": {
            "description": "A string containing the human-readable address of this place.\n\nOften this address is equivalent to the postal address. Note that some countries, such as the United Kingdom, do not allow distribution of true postal addresses due to licensing restrictions.\n\nThe formatted address is logically composed of one or more address components. For example, the address \"111 8th Avenue, New York, NY\" consists of the following components: \"111\" (the street number), \"8th Avenue\" (the route), \"New York\" (the city) and \"NY\" (the US state).\n\nDo not parse the formatted address programmatically. Instead you should use the individual address components, which the API response includes in addition to the formatted address field.\n",
            "type": "string",
            "example": "48 Pirrama Rd, Pyrmont NSW 2009, Australia"
          },
          "formatted_phone_number": {
            "description": "Contains the place's phone number in its [local format](http://en.wikipedia.org/wiki/Local_conventions_for_writing_telephone_numbers).",
            "type": "string",
            "example": "(02) 9374 4000"
          },
          "geometry": {
            "description": "Contains the location and viewport for the location.",
            "$ref": "#/components/schemas/Geometry"
          },
          "icon": {
            "description": "Contains the URL of a suggested icon which may be displayed to the user when indicating this result on a map.",
            "type": "string",
            "example": "https://maps.gstatic.com/mapfiles/place_api/icons/v1/png_71/generic_business-71.png"
          },
          "icon_background_color": {
            "description": "Contains the default HEX color code for the place's category.",
            "type": "string"
          },
          "icon_mask_base_uri": {
            "description": "Contains the URL of a recommended icon, minus the `.svg` or `.png` file type extension.",
            "type": "string"
          },
          "international_phone_number": {
            "description": "Contains the place's phone number in international format. International format includes the country code, and is prefixed with the plus, +, sign. For example, the international_phone_number for Google's Sydney, Australia office is `+61 2 9374 4000`.",
            "type": "string",
            "example": "+61 2 9374 4000"
          },
          "name": {
            "description": "Contains the human-readable name for the returned result. For `establishment` results, this is usually the canonicalized business name.",
            "type": "string",
            "example": "Google Workplace 6"
          },
          "opening_hours": {
            "description": "Contains the regular hours of operation.",
            "$ref": "#/components/schemas/PlaceOpeningHours"
          },
          "permanently_closed": {
            "deprecated": true,
            "description": "Use `business_status` to get the operational status of businesses.",
            "type": "boolean"
          },
          "photos": {
            "description": "An array of photo objects, each containing a reference to an image. A request may return up to ten photos. More information about place photos and how you can use the images in your application can be found in the [Place Photos](https://developers.google.com/maps/documentation/places/web-service/photos) documentation.",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PlacePhoto"
            }
          },
          "place_id": {
            "description": "A textual identifier that uniquely identifies a place. To retrieve information about the place, pass this identifier in the `place_id` field of a Places API request. For more information about place IDs, see the [place ID overview](https://developers.google.com/maps/documentation/places/web-service/place-id).",
            "type": "string",
            "example": "ChIJN1t_tDeuEmsRUsoyG83frY4"
          },
          "plus_code": {
            "description": "An encoded location reference, derived from latitude and longitude coordinates, that represents an area: 1/8000th of a degree by 1/8000th of a degree (about 14m x 14m at the equator) or smaller. Plus codes can be used as a replacement for street addresses in places where they do not exist (where buildings are not numbered or streets are not named). See [Open Location Code](https://en.wikipedia.org/wiki/Open_Location_Code) and [plus codes](https://plus.codes/).\n",
            "$ref": "#/components/schemas/PlusCode"
          },
          "price_level": {
            "description": "The price level of the place, on a scale of 0 to 4. The exact amount indicated by a specific value will vary from region to region. Price levels are interpreted as follows:\n- 0 Free\n- 1 Inexpensive\n- 2 Moderate\n- 3 Expensive\n- 4 Very Expensive\n",
            "type": "number"
          },
          "rating": {
            "description": "Contains the place's rating, from 1.0 to 5.0, based on aggregated user reviews.",
            "type": "number",
            "example": 4.1
          },
          "reference": {
            "deprecated": true,
            "type": "string"
          },
          "reservable": {
            "description": "Specifies if the place supports reservations.",
            "type": "boolean"
          },
          "reviews": {
            "description": "A JSON array of up to five reviews. By default, the reviews are sorted in order of relevance. Use the `reviews_sort` request parameter to control sorting.\n\n- For `most_relevant` (default), reviews are sorted by relevance; the service will bias the results to return reviews originally written in the preferred language.\n- For `newest`, reviews are sorted in chronological order; the preferred language does not affect the sort order.\nGoogle recommends indicating to users whether results are ordered by `most_relevant` or `newest`.\n",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PlaceReview"
            }
          },
          "serves_beer": {
            "description": "Specifies if the place serves beer.",
            "type": "boolean"
          },
          "serves_breakfast": {
            "description": "Specifies if the place serves breakfast.",
            "type": "boolean"
          },
          "serves_brunch": {
            "description": "Specifies if the place serves brunch.",
            "type": "boolean"
          },
          "serves_dinner": {
            "description": "Specifies if the place serves dinner.",
            "type": "boolean"
          },
          "serves_lunch": {
            "description": "Specifies if the place serves lunch.",
            "type": "boolean"
          },
          "serves_vegetarian_food": {
            "description": "Specifies if the place serves vegetarian food.",
            "type": "boolean"
          },
          "serves_wine": {
            "description": "Specifies if the place serves wine.",
            "type": "boolean"
          },
          "scope": {
            "deprecated": true,
            "type": "string"
          },
          "secondary_opening_hours": {
            "description": "Contains an array of entries for the next seven days including information about secondary hours of a business. Secondary hours are different from a business's main hours. For example, a restaurant can specify drive through hours or delivery hours as its secondary hours. This field populates the `type` subfield, which draws from a predefined list of opening hours types (such as `DRIVE_THROUGH`, `PICKUP`, or `TAKEOUT`) based on the types of the place. This field includes the `special_days` subfield of all hours, set for dates that have exceptional hours.",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PlaceOpeningHours"
            }
          },
          "takeout": {
            "description": "Specifies if the business supports takeout.",
            "type": "boolean"
          },
          "types": {
            "description": "Contains an array of feature types describing the given result. See the list of [supported types](https://developers.google.com/maps/documentation/places/web-service/supported_types#table2).",
            "type": "array",
            "items": {
              "type": "string"
            },
            "example": [
              "point_of_interest",
              "establishment"
            ]
          },
          "url": {
            "description": "Contains the URL of the official Google page for this place. This will be the Google-owned page that contains the best available information about the place. Applications must link to or embed this page on any screen that shows detailed results about the place to the user.",
            "type": "string",
            "example": "https://maps.google.com/?cid=10281119596374313554"
          },
          "user_ratings_total": {
            "description": "The total number of reviews, with or without text, for this place.",
            "type": "number",
            "example": 931
          },
          "utc_offset": {
            "description": "Contains the number of minutes this place’s current timezone is offset from UTC. For example, for places in Sydney, Australia during daylight saving time this would be 660 (+11 hours from UTC), and for places in California outside of daylight saving time this would be -480 (-8 hours from UTC).",
            "type": "number",
            "example": 600
          },
          "vicinity": {
            "description": "For establishment (`types:[\"establishment\", ...])` results only, the `vicinity` field contains a simplified address for the place, including the street name, street number, and locality, but not the province/state, postal code, or country.\n\nFor all other results, the `vicinity` field contains the name of the narrowest political (`types:[\"political\", ...]`) feature that is present in the address of the result.\n\nThis content is meant to be read as-is. Do not programmatically parse the formatted address.\n",
            "type": "string",
            "example": "48 Pirrama Road, Pyrmont"
          },
          "website": {
            "description": "The authoritative website for this place, such as a business' homepage.",
            "type": "string",
            "example": "http://google.com"
          },
          "wheelchair_accessible_entrance": {
            "description": "Specifies if the place has an entrance that is wheelchair-accessible.",
            "type": "boolean"
          }
        }
      }

Expected behavior

num? values should be parsed using tryParse

rating: num.tryParse('${json[r'rating']}'),

Logs

No response

Screenshots

No response

Platform

macOS

Library version

^5.0.2

Flutter version

3.19.2

Flutter channel

stable

Additional context

No response

jaustin42 commented 7 months ago

I did a temporary work around but had to make them all optional.

sed -i 's/num.parse/num.tryParse/g' lib/model/*.dart

jaustin42 commented 5 months ago

To follow up on this, it is not a bug in the dart code generator. The server code just needs to add the nullable option and not just the not required option. The code generator then does this:

numProperty: json[r'numProperty'] == null
       ? null
       : num.parse('${json[r'numProperty']}'),

This particular server side is using the Java annotations:

@Schema(requiredMode = Schema.RequiredMode.NOT_REQUIRED, nullable = true)
private BigDecimal numProperty;
gibahjoe commented 1 week ago

Closing this as its a server issue. Dont hessitate to reopen if you disagree