Skip to content
This repository has been archived by the owner on Feb 4, 2025. It is now read-only.

FromJson returns null when json doesn't contain required fields #3077

Merged
merged 4 commits into from
Aug 10, 2024

Conversation

atorresveiga
Copy link
Contributor

@atorresveiga atorresveiga commented Aug 10, 2024

Description

This small PR fixes a crash that happens when trying to create a WCMetaData from a JSON that does NOT contain any of the required fields ID, KEY, VALUE. When the JSON doesn't have any of the required fields now, the fromJson function will return null. If all the required fields are present, the fromJson function will return the expected WCMetaData.

Here is a sample of a response triggering the NPE

Full response
{
  "data": [
    {
      "id": 27,
      "name": "Album",
      "slug": "album",
      "permalink": "https://superlativecentaur.wpcomstaging.com/product/album/",
      "date_created": "2023-01-13T10:31:15",
      "date_created_gmt": "2023-01-13T10:31:15",
      "date_modified": "2024-08-07T18:37:06",
      "date_modified_gmt": "2024-08-07T17:37:06",
      "type": "simple",
      "status": "publish",
      "featured": false,
      "catalog_visibility": "visible",
      "description": "<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum sagittis orci ac odio dictum tincidunt. Donec ut metus leo. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Sed luctus, dui eu sagittis sodales, nulla nibh sagittis augue, vel porttitor diam enim non metus. Vestibulum aliquam augue neque. Phasellus tincidunt odio eget ullamcorper efficitur. Cras placerat ut turpis pellentesque vulputate. Nam sed consequat tortor. Curabitur finibus sapien dolor. Ut eleifend tellus nec erat pulvinar dignissim. Nam non arcu purus. Vivamus et massa massa. Est nam.</p>\n",
      "short_description": "<p>This is a simple, virtual product.</p>\n",
      "sku": "woo-album",
      "price": "20",
      "regular_price": "20",
      "sale_price": "",
      "date_on_sale_from": null,
      "date_on_sale_from_gmt": null,
      "date_on_sale_to": null,
      "date_on_sale_to_gmt": null,
      "on_sale": false,
      "purchasable": true,
      "total_sales": 71,
      "virtual": true,
      "downloadable": true,
      "downloads": [
        {
          "id": "4919d678-888f-45b8-a8f3-2b75c7ee12f9",
          "name": "Single 1",
          "file": "https://demo.woothemes.com/woocommerce/wp-content/uploads/sites/56/2017/08/single.jpg"
        },
        {
          "id": "d79a5441-c5cc-4111-bd22-5c6a9ade37a1",
          "name": "Single 2",
          "file": "https://demo.woothemes.com/woocommerce/wp-content/uploads/sites/56/2017/08/album.jpg"
        }
      ],
      "download_limit": 1,
      "download_expiry": 1,
      "external_url": "",
      "button_text": "",
      "tax_status": "taxable",
      "tax_class": "",
      "manage_stock": false,
      "stock_quantity": null,
      "backorders": "no",
      "backorders_allowed": false,
      "backordered": false,
      "low_stock_amount": null,
      "sold_individually": false,
      "weight": "",
      "dimensions": {
        "length": "",
        "width": "",
        "height": ""
      },
      "shipping_required": false,
      "shipping_taxable": false,
      "shipping_class": "",
      "shipping_class_id": 0,
      "reviews_allowed": true,
      "average_rating": "5.00",
      "rating_count": 1,
      "upsell_ids": [],
      "cross_sell_ids": [],
      "parent_id": 0,
      "purchase_note": "",
      "categories": [
        {
          "id": 1364,
          "name": "Music",
          "slug": "music"
        }
      ],
      "tags": [],
      "images": [
        {
          "id": 56,
          "date_created": "2023-01-13T10:31:18",
          "date_created_gmt": "2023-01-13T10:31:18",
          "date_modified": "2024-05-14T14:16:26",
          "date_modified_gmt": "2024-05-14T12:16:26",
          "src": "https://superlativecentaur.wpcomstaging.com/wp-content/uploads/2023/01/album-1.jpg",
          "name": "album-1.jpg",
          "alt": ""
        }
      ],
      "attributes": [],
      "default_attributes": [],
      "variations": [],
      "grouped_products": [],
      "menu_order": 0,
      "price_html": "<span class=\"woocommerce-Price-amount amount\"><bdi><span class=\"woocommerce-Price-currencySymbol\">&#36;</span>20.00</bdi></span>",
      "related_ids": [
        28,
        416
      ],
      "meta_data": [
        {
          "id": 615,
          "key": "_wpcom_is_markdown",
          "value": "1"
        },
        {
          "id": 618,
          "key": "_wpas_done_all",
          "value": "1"
        },
        {
          "id": 1626,
          "key": "_last_editor_used_jetpack",
          "value": "classic-editor"
        },
        {
          "id": 2651,
          "key": "_wc_gla_synced_at",
          "value": "1723052230"
        },
        {
          "id": 2652,
          "key": "_wc_gla_sync_status",
          "value": "synced"
        },
        {
          "id": 2653,
          "key": "_wc_gla_visibility",
          "value": "sync-and-show"
        },
        {
          "id": 2654,
          "key": "_wc_gla_google_ids",
          "value": {
            "US": "online:en:US:gla_27"
          }
        },
        {
          "id": 8190,
          "key": "_product_addons",
          "value": []
        },
        {
          "id": 8191,
          "key": "_product_addons_exclude_global",
          "value": "0"
        },
        {
          "id": 8192,
          "key": "group_of_quantity",
          "value": "4"
        },
        {
          "id": 8193,
          "key": "minimum_allowed_quantity",
          "value": ""
        },
        {
          "id": 8194,
          "key": "maximum_allowed_quantity",
          "value": ""
        },
        {
          "id": 8195,
          "key": "minmax_do_not_count",
          "value": "no"
        },
        {
          "id": 8196,
          "key": "minmax_cart_exclude",
          "value": "no"
        },
        {
          "id": 8197,
          "key": "minmax_category_group_of_exclude",
          "value": "no"
        },
        {
          "id": 8198,
          "key": "_subscription_one_time_shipping",
          "value": "no"
        },
        {
          "id": 8199,
          "key": "_wcsatt_force_subscription",
          "value": "no"
        },
        {
          "id": 8200,
          "key": "_wcsatt_disabled",
          "value": "yes"
        },
        {
          "id": 45310,
          "key": "_wc_gla_mc_status",
          "value": "disapproved"
        },
        {
          "key": "_satt_data",
          "value": {
            "subscription_schemes": []
          }
        }
      ],
      "stock_status": "instock",
      "has_options": true,
      "post_password": "",
      "composite_virtual": false,
      "composite_layout": "",
      "composite_add_to_cart_form_location": "",
      "composite_editable_in_cart": false,
      "composite_sold_individually_context": "",
      "composite_shop_price_calc": "",
      "composite_components": [],
      "composite_scenarios": [],
      "bundled_by": [
        "404",
        "404"
      ],
      "bundle_stock_status": "instock",
      "bundle_stock_quantity": null,
      "bundle_virtual": false,
      "bundle_layout": "",
      "bundle_add_to_cart_form_location": "",
      "bundle_editable_in_cart": false,
      "bundle_sold_individually_context": "",
      "bundle_item_grouping": "",
      "bundle_min_size": "",
      "bundle_max_size": "",
      "bundle_price": [],
      "bundled_items": [],
      "bundle_sell_ids": [],
      "group_of_quantity": 4,
      "min_quantity": 0,
      "max_quantity": "",
      "exclude_order_quantity_value_rules": "no",
      "exclude_category_quantity_rules": "no",
      "combine_variations": "no",
      "exclude_global_add_ons": false,
      "addons": [
        {
          "name": "As a Gift",
          "type": "checkbox",
          "position": 0,
          "required": true,
          "title_format": "heading",
          "description_enable": true,
          "description": "This will wrap your product as a gift",
          "placeholder_enable": false,
          "placeholder": null,
          "display": "select",
          "restrictions_type": "any_text",
          "adjust_price": false,
          "price": "",
          "price_type": "flat_fee",
          "restrictions": false,
          "min": 0,
          "max": 0,
          "options": [
            {
              "label": "Yes",
              "price": "2",
              "price_type": "quantity_based",
              "image": 0
            },
            {
              "label": "No",
              "price": "",
              "price_type": "quantity_based",
              "image": 0
            }
          ],
          "id": 1673993127
        }
      ],
      "jetpack_publicize_connections": [],
      "class_list": {
        "0": "post-27",
        "1": "product",
        "2": "type-product",
        "3": "status-publish",
        "4": "has-post-thumbnail",
        "6": "product_cat-music",
        "8": "first",
        "9": "instock",
        "10": "downloadable",
        "11": "virtual",
        "12": "taxable",
        "13": "purchasable",
        "14": "product-type-simple"
      },
      "jetpack_sharing_enabled": true,
      "jetpack_likes_enabled": true,
      "brands": [],
      "google_listings_and_ads__channel_visibility": {
        "is_visible": true,
        "channel_visibility": "sync-and-show",
        "sync_status": "synced",
        "issues": []
      },
      "_links": {
        "self": [
          {
            "href": "https://superlativecentaur.wpcomstaging.com/wp-json/wc/v3/products/27"
          }
        ],
        "collection": [
          {
            "href": "https://superlativecentaur.wpcomstaging.com/wp-json/wc/v3/products"
          }
        ]
      }
    },
    {
      "id": 190,
      "name": "Premium Quality",
      "slug": "super-awesome-bundle",
      "permalink": "https://superlativecentaur.wpcomstaging.com/product/super-awesome-bundle/",
      "date_created": "2023-01-24T14:51:00",
      "date_created_gmt": "2023-01-24T14:51:00",
      "date_modified": "2023-12-18T12:56:35",
      "date_modified_gmt": "2023-12-18T12:56:35",
      "type": "simple",
      "status": "publish",
      "featured": false,
      "catalog_visibility": "visible",
      "description": "<p>Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vestibulum tortor quam, feugiat vitae, ultricies eget, tempor sit amet, ante. Donec eu libero sit amet quam egestas semper. Aenean ultricies mi vitae est. Mauris placerat eleifend leo.</p>\n",
      "short_description": "<p>Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas.</p>\n",
      "sku": "",
      "price": "21.99",
      "regular_price": "21.99",
      "sale_price": "",
      "date_on_sale_from": null,
      "date_on_sale_from_gmt": null,
      "date_on_sale_to": null,
      "date_on_sale_to_gmt": null,
      "on_sale": false,
      "purchasable": true,
      "total_sales": 6,
      "virtual": false,
      "downloadable": false,
      "downloads": [],
      "download_limit": -1,
      "download_expiry": -1,
      "external_url": "",
      "button_text": "",
      "tax_status": "taxable",
      "tax_class": "",
      "manage_stock": false,
      "stock_quantity": null,
      "backorders": "no",
      "backorders_allowed": false,
      "backordered": false,
      "low_stock_amount": null,
      "sold_individually": true,
      "weight": "",
      "dimensions": {
        "length": "",
        "width": "",
        "height": ""
      },
      "shipping_required": true,
      "shipping_taxable": true,
      "shipping_class": "",
      "shipping_class_id": 0,
      "reviews_allowed": true,
      "average_rating": "5.00",
      "rating_count": 1,
      "upsell_ids": [
        36,
        35
      ],
      "cross_sell_ids": [
        17
      ],
      "parent_id": 0,
      "purchase_note": "",
      "categories": [],
      "tags": [],
      "images": [
        {
          "id": 945,
          "date_created": "2023-12-18T12:52:54",
          "date_created_gmt": "2023-12-18T12:52:54",
          "date_modified": "2023-12-18T12:52:54",
          "date_modified_gmt": "2023-12-18T12:52:54",
          "src": "https://superlativecentaur.wpcomstaging.com/wp-content/uploads/2023/12/T_2_front.jpg",
          "name": "T_2_front.jpg",
          "alt": ""
        },
        {
          "id": 946,
          "date_created": "2023-12-18T12:52:54",
          "date_created_gmt": "2023-12-18T12:52:54",
          "date_modified": "2023-12-18T12:52:54",
          "date_modified_gmt": "2023-12-18T12:52:54",
          "src": "https://superlativecentaur.wpcomstaging.com/wp-content/uploads/2023/12/T_2_back.jpg",
          "name": "T_2_back.jpg",
          "alt": ""
        }
      ],
      "attributes": [],
      "default_attributes": [],
      "variations": [],
      "grouped_products": [],
      "menu_order": 0,
      "price_html": "<span class=\"woocommerce-Price-amount amount\"><bdi><span class=\"woocommerce-Price-currencySymbol\">&#36;</span>21.99</bdi></span><small class=\"wcsatt-sub-options\"> <span class=\"wcsatt-dash\">&mdash;</span> or subscribe and save up to</small> <span class=\"wcsatt-sub-discount\">30&#37;</span><small></small>",
      "related_ids": [],
      "meta_data": [
        {
          "id": 3938,
          "key": "_wpcom_is_markdown",
          "value": "1"
        },
        {
          "id": 3939,
          "key": "_last_editor_used_jetpack",
          "value": "classic-editor"
        },
        {
          "id": 3944,
          "key": "_product_addons",
          "value": [
            {
              "name": "Optional gift message",
              "title_format": "label",
              "description_enable": 0,
              "description": "",
              "type": "custom_textarea",
              "display": "select",
              "position": 0,
              "required": 0,
              "restrictions": 0,
              "restrictions_type": "any_text",
              "adjust_price": 0,
              "price_type": "flat_fee",
              "price": "",
              "min": 0,
              "max": 0,
              "id": 1702904153,
              "options": [
                {
                  "label": "",
                  "price": "",
                  "image": "",
                  "price_type": "flat_fee"
                }
              ]
            }
          ]
        },
        {
          "id": 3945,
          "key": "_product_addons_exclude_global",
          "value": "0"
        },
        {
          "id": 3962,
          "key": "_wc_gla_visibility",
          "value": "sync-and-show"
        },
        {
          "id": 3963,
          "key": "group_of_quantity",
          "value": ""
        },
        {
          "id": 3964,
          "key": "minimum_allowed_quantity",
          "value": ""
        },
        {
          "id": 3965,
          "key": "maximum_allowed_quantity",
          "value": ""
        },
        {
          "id": 3966,
          "key": "minmax_do_not_count",
          "value": "no"
        },
        {
          "id": 3967,
          "key": "minmax_cart_exclude",
          "value": "no"
        },
        {
          "id": 3968,
          "key": "minmax_category_group_of_exclude",
          "value": "no"
        },
        {
          "id": 3972,
          "key": "_wcpb_min_qty_limit",
          "value": ""
        },
        {
          "id": 3973,
          "key": "_wcpb_max_qty_limit",
          "value": ""
        },
        {
          "id": 3974,
          "key": "_wc_pb_virtual_bundle",
          "value": "no"
        },
        {
          "id": 3975,
          "key": "_wc_pb_layout_style",
          "value": "default"
        },
        {
          "id": 3976,
          "key": "_wc_pb_group_mode",
          "value": "parent"
        },
        {
          "id": 3978,
          "key": "_wc_pb_base_regular_price",
          "value": "59.0"
        },
        {
          "id": 3979,
          "key": "_wc_pb_base_sale_price",
          "value": ""
        },
        {
          "id": 3980,
          "key": "_wc_pb_edit_in_cart",
          "value": "no"
        },
        {
          "id": 3981,
          "key": "_wc_pb_aggregate_weight",
          "value": "no"
        },
        {
          "id": 3982,
          "key": "_wc_pb_sold_individually_context",
          "value": "configuration"
        },
        {
          "id": 3983,
          "key": "_wc_pb_add_to_cart_form_location",
          "value": "default"
        },
        {
          "id": 3984,
          "key": "_wc_pb_base_price",
          "value": "59.0"
        },
        {
          "id": 3985,
          "key": "_wc_gla_isBundle",
          "value": "yes"
        },
        {
          "id": 3990,
          "key": "_wpas_done_all",
          "value": "1"
        },
        {
          "id": 10413,
          "key": "_wc_gla_sync_status",
          "value": "synced"
        },
        {
          "id": 10414,
          "key": "_wc_pb_bundle_stock_quantity",
          "value": "0"
        },
        {
          "id": 10415,
          "key": "wc_bis_previous_stock",
          "value": "0"
        },
        {
          "id": 10416,
          "key": "_subscription_one_time_shipping",
          "value": "no"
        },
        {
          "id": 10417,
          "key": "_wcsatt_force_subscription",
          "value": "no"
        },
        {
          "id": 10418,
          "key": "_wc_pre_orders_enabled",
          "value": "no"
        },
        {
          "id": 10419,
          "key": "_wc_pre_orders_fee",
          "value": ""
        },
        {
          "id": 10420,
          "key": "_wc_pb_bundled_items_stock_status",
          "value": "outofstock"
        },
        {
          "id": 27045,
          "key": "_wc_gla_synced_at",
          "value": "1722740439"
        },
        {
          "id": 27046,
          "key": "_wc_gla_google_ids",
          "value": {
            "US": "online:en:US:gla_190"
          }
        },
        {
          "id": 27047,
          "key": "_subscription_downloads_ids",
          "value": ""
        },
        {
          "id": 45304,
          "key": "_wc_gla_mc_status",
          "value": "disapproved"
        },
        {
          "key": "_satt_data",
          "value": {
            "subscription_schemes": {
              "1_month_6": {},
              "1_year": {},
              "1_month": {}
            },
            "has_forced_subscription": "",
            "active_subscription_scheme_key": null
          }
        },
        {
          "key": "_subscription_payment_sync_date",
          "value": 0
        }
      ],
      "stock_status": "instock",
      "has_options": true,
      "post_password": "",
      "composite_virtual": false,
      "composite_layout": "",
      "composite_add_to_cart_form_location": "",
      "composite_editable_in_cart": false,
      "composite_sold_individually_context": "",
      "composite_shop_price_calc": "",
      "composite_components": [],
      "composite_scenarios": [],
      "bundled_by": [],
      "bundle_stock_status": "instock",
      "bundle_stock_quantity": null,
      "bundle_virtual": false,
      "bundle_layout": "",
      "bundle_add_to_cart_form_location": "",
      "bundle_editable_in_cart": false,
      "bundle_sold_individually_context": "",
      "bundle_item_grouping": "",
      "bundle_min_size": "",
      "bundle_max_size": "",
      "bundle_price": [],
      "bundled_items": [],
      "bundle_sell_ids": [],
      "group_of_quantity": 0,
      "min_quantity": 0,
      "max_quantity": "",
      "exclude_order_quantity_value_rules": "no",
      "exclude_category_quantity_rules": "no",
      "combine_variations": "no",
      "exclude_global_add_ons": false,
      "addons": [
        {
          "name": "Optional gift message",
          "type": "custom_textarea",
          "position": 0,
          "required": false,
          "title_format": "label",
          "description_enable": false,
          "description": "",
          "placeholder_enable": false,
          "placeholder": null,
          "display": "select",
          "restrictions_type": "any_text",
          "adjust_price": false,
          "price": "",
          "price_type": "flat_fee",
          "restrictions": false,
          "min": 0,
          "max": 0,
          "options": [],
          "id": 1702904153
        },
        {
          "name": "As a Gift",
          "type": "checkbox",
          "position": 0,
          "required": true,
          "title_format": "heading",
          "description_enable": true,
          "description": "This will wrap your product as a gift",
          "placeholder_enable": false,
          "placeholder": null,
          "display": "select",
          "restrictions_type": "any_text",
          "adjust_price": false,
          "price": "",
          "price_type": "flat_fee",
          "restrictions": false,
          "min": 0,
          "max": 0,
          "options": [
            {
              "label": "Yes",
              "price": "2",
              "price_type": "quantity_based",
              "image": 0
            },
            {
              "label": "No",
              "price": "",
              "price_type": "quantity_based",
              "image": 0
            }
          ],
          "id": 1673993127
        }
      ],
      "jetpack_publicize_connections": [],
      "class_list": {
        "0": "post-190",
        "1": "product",
        "2": "type-product",
        "3": "status-publish",
        "4": "has-post-thumbnail",
        "7": "",
        "8": "instock",
        "9": "sold-individually",
        "10": "taxable",
        "11": "shipping-taxable",
        "12": "purchasable",
        "13": "product-type-simple"
      },
      "jetpack_sharing_enabled": true,
      "jetpack_likes_enabled": true,
      "brands": [],
      "google_listings_and_ads__channel_visibility": {
        "is_visible": true,
        "channel_visibility": "sync-and-show",
        "sync_status": "synced",
        "issues": []
      },
      "_links": {
        "self": [
          {
            "href": "https://superlativecentaur.wpcomstaging.com/wp-json/wc/v3/products/190"
          }
        ],
        "collection": [
          {
            "href": "https://superlativecentaur.wpcomstaging.com/wp-json/wc/v3/products"
          }
        ]
      }
    }
  ]
}

Testing

Unit test should cover all edge cases

internal fun fromJson(json: JsonObject): WCMetaData? {
return if (json.has(ID) && json.has(KEY) && json.has(VALUE)) {
WCMetaData(
id = json[ID].asLong,
Copy link
Contributor Author

@atorresveiga atorresveiga Aug 10, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@hichamboushaba I'm assuming that ID, KEY, and VALUE are mandatory. Considering these values as mandatory, if one of those is missing, fromJson will return null

Copy link
Member

@hichamboushaba hichamboushaba Aug 11, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @atorresveiga for the fix, I marked all the fields as required because the API's documentation lists them all as so.
Now that we know the API can return unexpected results (sadly like most other WP APIs), I'm thinking we can take this a step further, we should probably wrap the whole logic in a runCatching and return null for any unexpected result (for example an id that's not a Long, or a key that's not a String).

Unless you have any reservations about this approach, I'll apply this to my pending PR, please let me know what you think.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here is the change, please take a look and let me know what you think: c578de7

@atorresveiga atorresveiga removed the request for review from hichamboushaba August 10, 2024 04:07
@atorresveiga atorresveiga merged commit dbb16f6 into trunk Aug 10, 2024
13 checks passed
@atorresveiga atorresveiga deleted the fix/metadata-no-id-npe branch August 10, 2024 04:08
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants