facebook / facebook-java-business-sdk

Java SDK for Meta Marketing APIs
https://developers.facebook.com/docs/business-sdk
Other
395 stars 326 forks source link

com.facebook.ads.sdk.APIException$MalformedResponseException: Invalid response string #370

Open JohnNguyenTR opened 2 years ago

JohnNguyenTR commented 2 years ago

Which SDK version are you using?

I'm upgrading my FB Extract API app from FB Java business sdk v11 to v12.0.1

I run a test to extract all Adset field for an account using the Adset.java

What's the issue?

I got the error: com.facebook.ads.sdk.APIException$MalformedResponseException: Invalid response string ....

at com.facebook.ads.sdk.AdSet.parseResponse(AdSet.java:348) at com.facebook.ads.sdk.AdSet$APIRequestGet.parseResponse(AdSet.java:5124) at com.facebook.ads.sdk.AdSet$APIRequestGet.execute(AdSet.java:5135) at com.facebook.ads.sdk.AdSet$APIRequestGet.execute(AdSet.java:5129) at com.facebook.ads.sdk.AdSet.fetchById(AdSet.java:193)

Steps/Sample code to reproduce the issue

public String getAdSetData(String adSetId, APIContext context) throws APIException {

    try {

           AdSet apiResponse = AdSet.fetchById((String) adSetId, context);
        // AdSet apiResponse = AdSet.fetchByIds( .....)
        if (apiResponse == null) {
            return "null";
        }
        GsonBuilder builder = new GsonBuilder();
        Gson gson = builder.create();
        JsonObject jsonObject = apiResponse.getRawResponseAsJsonObject();

        LinkedTreeMap dataMap = gson.fromJson(jsonObject, LinkedTreeMap.class);

        if (apiResponse.getFieldTargeting() != null) {
                String targetingString = apiResponse.getFieldTargeting().toString();
            JsonObject targeting = gson.fromJson(targetingString, JsonObject.class);
            parseAdSetTargeting(dataMap, targeting);

        }

        return gson.toJson(dataMap);

    } catch (Exception e) {
        e.printStackTrace();
        log.error("Exception in getAdSetData(): " + e.getMessage());
        throw e;
    }

    //return null;
}

def "Should get Ad Account Campaign Adsets Data"() { when: def adAcctCampaigns = facebookService.getAdSetData("23842996206500470", context) println adAcctCampaigns then: adAcctCampaigns != null }

Observed Results:

JohnNguyenTR commented 2 years ago

Comparing Adset.java version 11 and 12.0.1, I notice that there are two additional fields in the Adset.java version 12.0.1: "existing_customer_budget_percentage" and "targeting_optimization_types". My error appears to be related with the new filed " "targeting_optimization_types". Does anyone have issue with that new field "targeting_optimization_types"?

JohnNguyenTR commented 2 years ago

Just a note: If I comment the new field in both places of the public static final String[] FIELDS = {" ...., then that error is gone. However, the returned json does not contain that targeting_optimization_types anymore. Do you have any better way to deal with that "targeting_optimization_types" new field?

vp-cs commented 2 years ago

I've got the same issue. I had to remove from request both of those new fields to make it work (existing_customer_budget_percentage,targeting_optimization_types).

stcheng commented 1 year ago

We are aware of this issue. The root cause is that the type targeting_optimization_types is no longer map<string, int> but list<map<string, int>>. We are working on a fix but right now here is a patch:

diff --git a/sdk/servers/java/release/src/main/java/com/facebook/ads/sdk/AdSet.java b/sdk/servers/java/release/src/main/java/com/facebook/ads/sdk/AdSet.java
index e0a767f2..162cf60c 100644
--- a/sdk/servers/java/release/src/main/java/com/facebook/ads/sdk/AdSet.java
+++ b/sdk/servers/java/release/src/main/java/com/facebook/ads/sdk/AdSet.java
@@ -158,7 +158,7 @@ public class AdSet extends APINode {
   @SerializedName("targeting")
   private Targeting mTargeting = null;
   @SerializedName("targeting_optimization_types")
-  private Map<String, Long> mTargetingOptimizationTypes = null;
+  private List<Map<String, Long>> mTargetingOptimizationTypes = null;
   @SerializedName("time_based_ad_rotation_id_blocks")
   private List<List<Long>> mTimeBasedAdRotationIdBlocks = null;
   @SerializedName("time_based_ad_rotation_intervals")
@@ -975,11 +975,11 @@ public class AdSet extends APINode {
     this.mTargeting = Targeting.getGson().fromJson(value, type);
     return this;
   }
-  public Map<String, Long> getFieldTargetingOptimizationTypes() {
+  public List<Map<String, Long>> getFieldTargetingOptimizationTypes() {
     return mTargetingOptimizationTypes;
   }

-  public AdSet setFieldTargetingOptimizationTypes(Map<String, Long> value) {
+  public AdSet setFieldTargetingOptimizationTypes(List<Map<String, Long>> value) {
     this.mTargetingOptimizationTypes = value;
     return this;
   }