The code samples below provide examples for managing Shopping campaigns using the AdWords API. Client Library.
Build a product partition tree for an ad group
// Copyright 2017 Google Inc. All Rights Reserved. // // 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 adwords.axis.v201809.shoppingcampaigns; import static com.google.api.ads.common.lib.utils.Builder.DEFAULT_CONFIGURATION_FILENAME; import com.beust.jcommander.Parameter; import com.google.api.ads.adwords.axis.factory.AdWordsServices; import com.google.api.ads.adwords.axis.utils.v201809.shopping.ProductDimensions; import com.google.api.ads.adwords.axis.utils.v201809.shopping.ProductPartitionNode; import com.google.api.ads.adwords.axis.utils.v201809.shopping.ProductPartitionTree; import com.google.api.ads.adwords.axis.v201809.cm.AdGroupCriterionOperation; import com.google.api.ads.adwords.axis.v201809.cm.AdGroupCriterionServiceInterface; import com.google.api.ads.adwords.axis.v201809.cm.ApiError; import com.google.api.ads.adwords.axis.v201809.cm.ApiException; import com.google.api.ads.adwords.axis.v201809.cm.ProductCanonicalConditionCondition; import com.google.api.ads.adwords.axis.v201809.cm.ProductDimensionType; import com.google.api.ads.adwords.lib.client.AdWordsSession; import com.google.api.ads.adwords.lib.factory.AdWordsServicesInterface; import com.google.api.ads.adwords.lib.utils.examples.ArgumentNames; import com.google.api.ads.common.lib.auth.OfflineCredentials; import com.google.api.ads.common.lib.auth.OfflineCredentials.Api; import com.google.api.ads.common.lib.conf.ConfigurationLoadException; import com.google.api.ads.common.lib.exception.OAuthException; import com.google.api.ads.common.lib.exception.ValidationException; import com.google.api.ads.common.lib.utils.examples.CodeSampleParams; import com.google.api.client.auth.oauth2.Credential; import java.rmi.RemoteException; import java.util.List; /** * This example clears out any existing ProductPartition criteria on the ad group and rebuilds the * tree to contain: * * <pre> *ROOT *ProductCanonicalCondition NEW $0.20 *ProductCanonicalCondition USED $0.10 *ProductCanonicalCondition null (everything else) * ProductBrand CoolBrand $0.90 * ProductBrand CheapBrand $0.01 * ProductBrand null (everything else) * ProductType Level1 Luggage & Bags $0.75 * ProductType Level1 null (everything else) $0.11 *</pre> * * <p>Credentials and properties in {@code fromFile()} are pulled from the * "ads.properties" file. See README for more info. */ public class AddProductPartitionTree { private static class AddProductPartitionTreeParams extends CodeSampleParams { @Parameter(names = ArgumentNames.AD_GROUP_ID, required = true) private Long adGroupId; } public static void main(String[] args) { AdWordsSession session; try { // Generate a refreshable OAuth2 credential. Credential oAuth2Credential = new OfflineCredentials.Builder() .forApi(Api.ADWORDS) .fromFile() .build() .generateCredential(); // Construct an AdWordsSession. session = new AdWordsSession.Builder().fromFile().withOAuth2Credential(oAuth2Credential).build(); } catch (ConfigurationLoadException cle) { System.err.printf( "Failed to load configuration from the %s file. Exception: %s%n", DEFAULT_CONFIGURATION_FILENAME, cle); return; } catch (ValidationException ve) { System.err.printf( "Invalid configuration in the %s file. Exception: %s%n", DEFAULT_CONFIGURATION_FILENAME, ve); return; } catch (OAuthException oe) { System.err.printf( "Failed to create OAuth credentials. Check OAuth settings in the %s file. " + "Exception: %s%n", DEFAULT_CONFIGURATION_FILENAME, oe); return; } AdWordsServicesInterface adWordsServices = AdWordsServices.getInstance(); AddProductPartitionTreeParams params = new AddProductPartitionTreeParams(); if (!params.parseArguments(args)) { // Either pass the required parameters for this example on the command line, or insert them // into the code here. See the parameter class definition above for descriptions. params.adGroupId = Long.parseLong("INSERT_AD_GROUP_ID_HERE"); } try { runExample(adWordsServices, session, params.adGroupId); } catch (ApiException apiException) { // ApiException is the base class for most exceptions thrown by an API request. Instances // of this exception have a message and a collection of ApiErrors that indicate the // type and underlying cause of the exception. Every exception object in the adwords.axis // packages will return a meaningful value from toString // // ApiException extends RemoteException, so this catch block must appear before the // catch block for RemoteException. System.err.println("Request failed due to ApiException. Underlying ApiErrors:"); if (apiException.getErrors() != null) { int i = 0; for (ApiError apiError : apiException.getErrors()) { System.err.printf(" Error %d: %s%n", i++, apiError); } } } catch (RemoteException re) { System.err.printf( "Request failed unexpectedly due to RemoteException: %s%n", re); } } /** * Runs the example. * * @param adWordsServices the services factory. * @param session the session. * @param adGroupId the ID of the ad group. * @throws ApiException if the API request failed with one or more service errors. * @throws RemoteException if the API request failed due to other errors. */ public static void runExample(AdWordsServicesInterface adWordsServices, AdWordsSession session, Long adGroupId) throws RemoteException { // Build a new ProductPartitionTree using the ad group's current set of criteria. ProductPartitionTree partitionTree = ProductPartitionTree.createAdGroupTree(adWordsServices, session, adGroupId); System.out.printf("Original tree:%n%s%n", partitionTree); // Clear out any existing criteria. ProductPartitionNode rootNode = partitionTree.getRoot().removeAllChildren(); // Make the root node a subdivision. rootNode = rootNode.asSubdivision(); // Add a unit node for condition = NEW. rootNode.addChild( ProductDimensions.createCanonicalCondition(ProductCanonicalConditionCondition.NEW)) .asBiddableUnit().setBid(200000L); // Add a unit node for condition = USED. rootNode.addChild( ProductDimensions.createCanonicalCondition(ProductCanonicalConditionCondition.USED)) .asBiddableUnit().setBid(100000L); // Add a subdivision node for condition = null (everything else). ProductPartitionNode otherConditionNode = rootNode.addChild(ProductDimensions.createCanonicalCondition(null)).asSubdivision(); // Add a unit node under condition = null for brand = "CoolBrand". otherConditionNode.addChild(ProductDimensions.createBrand("CoolBrand")).asBiddableUnit() .setBid(900000L); // Add a unit node under condition = null for brand = "CheapBrand". otherConditionNode.addChild(ProductDimensions.createBrand("CheapBrand")).asBiddableUnit() .setBid(10000L); // Add a subdivision node under condition = null for brand = null (everything else). ProductPartitionNode otherBrandNode = otherConditionNode.addChild(ProductDimensions.createBrand(null)).asSubdivision(); // Add unit nodes under condition = null/brand = null. // The value for each bidding category is a fixed ID for a specific // category. You can retrieve IDs for categories from the ConstantDataService. // See the 'GetProductCategoryTaxonomy' example for more details. // Add a unit node under condition = null/brand = null for product type // level 1 = 'Luggage & Bags'. otherBrandNode.addChild(ProductDimensions.createBiddingCategory( ProductDimensionType.BIDDING_CATEGORY_L1, -5914235892932915235L)).asBiddableUnit() .setBid(750000L); // Add a unit node under condition = null/brand = null for product type // level 1 = null (everything else). otherBrandNode.addChild( ProductDimensions.createBiddingCategory(ProductDimensionType.BIDDING_CATEGORY_L1, null)) .asBiddableUnit().setBid(110000L); // Get the ad group criterion service. AdGroupCriterionServiceInterface adGroupCriterionService = adWordsServices.get(session, AdGroupCriterionServiceInterface.class); // Make the mutate request, using the operations returned by the ProductPartitionTree. List<AdGroupCriterionOperation> mutateOperations = partitionTree.getMutateOperations(); if (mutateOperations.isEmpty()) { System.out.println("Skipping the mutate call because the original tree and the current tree " + "are logically identical."); } else { adGroupCriterionService.mutate(mutateOperations.toArray(new AdGroupCriterionOperation[0])); } // The request was successful, so create a new ProductPartitionTree based on the updated state // of the ad group. partitionTree = ProductPartitionTree.createAdGroupTree(adWordsServices, session, adGroupId); // Show the tree System.out.printf("Updated tree:%n%s%n", partitionTree); } }
Set a product scope for a campaign
// Copyright 2017 Google Inc. All Rights Reserved. // // 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 adwords.axis.v201809.shoppingcampaigns; import static com.google.api.ads.common.lib.utils.Builder.DEFAULT_CONFIGURATION_FILENAME; import com.beust.jcommander.Parameter; import com.google.api.ads.adwords.axis.factory.AdWordsServices; import com.google.api.ads.adwords.axis.v201809.cm.ApiError; import com.google.api.ads.adwords.axis.v201809.cm.ApiException; import com.google.api.ads.adwords.axis.v201809.cm.CampaignCriterion; import com.google.api.ads.adwords.axis.v201809.cm.CampaignCriterionOperation; import com.google.api.ads.adwords.axis.v201809.cm.CampaignCriterionReturnValue; import com.google.api.ads.adwords.axis.v201809.cm.CampaignCriterionServiceInterface; import com.google.api.ads.adwords.axis.v201809.cm.Operator; import com.google.api.ads.adwords.axis.v201809.cm.ProductBiddingCategory; import com.google.api.ads.adwords.axis.v201809.cm.ProductBrand; import com.google.api.ads.adwords.axis.v201809.cm.ProductCanonicalCondition; import com.google.api.ads.adwords.axis.v201809.cm.ProductCanonicalConditionCondition; import com.google.api.ads.adwords.axis.v201809.cm.ProductCustomAttribute; import com.google.api.ads.adwords.axis.v201809.cm.ProductDimension; import com.google.api.ads.adwords.axis.v201809.cm.ProductDimensionType; import com.google.api.ads.adwords.axis.v201809.cm.ProductOfferId; import com.google.api.ads.adwords.axis.v201809.cm.ProductScope; import com.google.api.ads.adwords.axis.v201809.cm.ProductType; import com.google.api.ads.adwords.lib.client.AdWordsSession; import com.google.api.ads.adwords.lib.factory.AdWordsServicesInterface; import com.google.api.ads.adwords.lib.utils.examples.ArgumentNames; import com.google.api.ads.common.lib.auth.OfflineCredentials; import com.google.api.ads.common.lib.auth.OfflineCredentials.Api; import com.google.api.ads.common.lib.conf.ConfigurationLoadException; import com.google.api.ads.common.lib.exception.OAuthException; import com.google.api.ads.common.lib.exception.ValidationException; import com.google.api.ads.common.lib.utils.examples.CodeSampleParams; import com.google.api.client.auth.oauth2.Credential; import java.rmi.RemoteException; /** * This example restricts the products that will be included in the * campaign by setting a ProductScope. * * <p>Credentials and properties in {@code fromFile()} are pulled from the * "ads.properties" file. See README for more info. */ public class AddProductScope { private static class AddProductScopeParams extends CodeSampleParams { @Parameter(names = ArgumentNames.CAMPAIGN_ID, required = true) private Long campaignId; } public static void main(String[] args) { AdWordsSession session; try { // Generate a refreshable OAuth2 credential. Credential oAuth2Credential = new OfflineCredentials.Builder() .forApi(Api.ADWORDS) .fromFile() .build() .generateCredential(); // Construct an AdWordsSession. session = new AdWordsSession.Builder().fromFile().withOAuth2Credential(oAuth2Credential).build(); } catch (ConfigurationLoadException cle) { System.err.printf( "Failed to load configuration from the %s file. Exception: %s%n", DEFAULT_CONFIGURATION_FILENAME, cle); return; } catch (ValidationException ve) { System.err.printf( "Invalid configuration in the %s file. Exception: %s%n", DEFAULT_CONFIGURATION_FILENAME, ve); return; } catch (OAuthException oe) { System.err.printf( "Failed to create OAuth credentials. Check OAuth settings in the %s file. " + "Exception: %s%n", DEFAULT_CONFIGURATION_FILENAME, oe); return; } AdWordsServicesInterface adWordsServices = AdWordsServices.getInstance(); AddProductScopeParams params = new AddProductScopeParams(); if (!params.parseArguments(args)) { // Either pass the required parameters for this example on the command line, or insert them // into the code here. See the parameter class definition above for descriptions. params.campaignId = Long.parseLong("INSERT_CAMPAIGN_ID_HERE"); } try { runExample(adWordsServices, session, params.campaignId); } catch (ApiException apiException) { // ApiException is the base class for most exceptions thrown by an API request. Instances // of this exception have a message and a collection of ApiErrors that indicate the // type and underlying cause of the exception. Every exception object in the adwords.axis // packages will return a meaningful value from toString // // ApiException extends RemoteException, so this catch block must appear before the // catch block for RemoteException. System.err.println("Request failed due to ApiException. Underlying ApiErrors:"); if (apiException.getErrors() != null) { int i = 0; for (ApiError apiError : apiException.getErrors()) { System.err.printf(" Error %d: %s%n", i++, apiError); } } } catch (RemoteException re) { System.err.printf( "Request failed unexpectedly due to RemoteException: %s%n", re); } } /** * Runs the example. * * @param adWordsServices the services factory. * @param session the session. * @param campaignId the ID of the shopping campaign. * @throws ApiException if the API request failed with one or more service errors. * @throws RemoteException if the API request failed due to other errors. */ public static void runExample( AdWordsServicesInterface adWordsServices, AdWordsSession session, Long campaignId) throws RemoteException { // Get the campaign criterion service. CampaignCriterionServiceInterface campaignCriterionService = adWordsServices.get(session, CampaignCriterionServiceInterface.class); ProductScope productScope = new ProductScope(); // This set of dimensions is for demonstration purposes only. It would be // extremely unlikely that you want to include so many dimensions in your // product scope. ProductBrand productBrand = new ProductBrand(); productBrand.setValue("Nexus"); ProductCanonicalCondition productCanonicalCondition = new ProductCanonicalCondition(); productCanonicalCondition.setCondition(ProductCanonicalConditionCondition.NEW); ProductCustomAttribute productCustomAttribute = new ProductCustomAttribute(); productCustomAttribute.setType(ProductDimensionType.CUSTOM_ATTRIBUTE_0); productCustomAttribute.setValue("my attribute value"); ProductOfferId productOfferId = new ProductOfferId(); productOfferId.setValue("book1"); ProductType productTypeLevel1Media = new ProductType(); productTypeLevel1Media.setType(ProductDimensionType.PRODUCT_TYPE_L1); productTypeLevel1Media.setValue("Media"); ProductType productTypeLevel2Books = new ProductType(); productTypeLevel2Books.setType(ProductDimensionType.PRODUCT_TYPE_L2); productTypeLevel2Books.setValue("Books"); // The value for the bidding category is a fixed ID for the 'Luggage & Bags' // category. You can retrieve IDs for categories from the ConstantDataService. // See the 'GetProductCategoryTaxonomy' example for more details. ProductBiddingCategory productBiddingCategory = new ProductBiddingCategory(); productBiddingCategory.setType(ProductDimensionType.BIDDING_CATEGORY_L1); productBiddingCategory.setValue(-5914235892932915235L); productScope.setDimensions(new ProductDimension[]{ productBrand, productCanonicalCondition, productCustomAttribute, productOfferId, productTypeLevel1Media, productTypeLevel2Books, productBiddingCategory}); CampaignCriterion campaignCriterion = new CampaignCriterion(); campaignCriterion.setCampaignId(campaignId); campaignCriterion.setCriterion(productScope); // Create operation. CampaignCriterionOperation criterionOperation = new CampaignCriterionOperation(); criterionOperation.setOperand(campaignCriterion); criterionOperation.setOperator(Operator.ADD); // Make the mutate request. CampaignCriterionReturnValue result = campaignCriterionService.mutate(new CampaignCriterionOperation[] {criterionOperation}); // Display the result. System.out.printf("Created a ProductScope criterion with ID %d.%n", result.getValue(0).getCriterion().getId()); } }
Add a Shopping campaign
// Copyright 2017 Google Inc. All Rights Reserved. // // 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 adwords.axis.v201809.shoppingcampaigns; import static com.google.api.ads.common.lib.utils.Builder.DEFAULT_CONFIGURATION_FILENAME; import com.beust.jcommander.Parameter; import com.google.api.ads.adwords.axis.factory.AdWordsServices; import com.google.api.ads.adwords.axis.utils.v201809.shopping.ProductPartitionTree; import com.google.api.ads.adwords.axis.v201809.cm.AdGroup; import com.google.api.ads.adwords.axis.v201809.cm.AdGroupAd; import com.google.api.ads.adwords.axis.v201809.cm.AdGroupAdOperation; import com.google.api.ads.adwords.axis.v201809.cm.AdGroupAdReturnValue; import com.google.api.ads.adwords.axis.v201809.cm.AdGroupAdServiceInterface; import com.google.api.ads.adwords.axis.v201809.cm.AdGroupCriterion; import com.google.api.ads.adwords.axis.v201809.cm.AdGroupCriterionOperation; import com.google.api.ads.adwords.axis.v201809.cm.AdGroupCriterionReturnValue; import com.google.api.ads.adwords.axis.v201809.cm.AdGroupCriterionServiceInterface; import com.google.api.ads.adwords.axis.v201809.cm.AdGroupOperation; import com.google.api.ads.adwords.axis.v201809.cm.AdGroupReturnValue; import com.google.api.ads.adwords.axis.v201809.cm.AdGroupServiceInterface; import com.google.api.ads.adwords.axis.v201809.cm.AdvertisingChannelType; import com.google.api.ads.adwords.axis.v201809.cm.ApiError; import com.google.api.ads.adwords.axis.v201809.cm.ApiException; import com.google.api.ads.adwords.axis.v201809.cm.BiddingStrategyConfiguration; import com.google.api.ads.adwords.axis.v201809.cm.BiddingStrategyType; import com.google.api.ads.adwords.axis.v201809.cm.Budget; import com.google.api.ads.adwords.axis.v201809.cm.Campaign; import com.google.api.ads.adwords.axis.v201809.cm.CampaignOperation; import com.google.api.ads.adwords.axis.v201809.cm.CampaignReturnValue; import com.google.api.ads.adwords.axis.v201809.cm.CampaignServiceInterface; import com.google.api.ads.adwords.axis.v201809.cm.CampaignStatus; import com.google.api.ads.adwords.axis.v201809.cm.Operator; import com.google.api.ads.adwords.axis.v201809.cm.ProductAd; import com.google.api.ads.adwords.axis.v201809.cm.Setting; import com.google.api.ads.adwords.axis.v201809.cm.ShoppingSetting; import com.google.api.ads.adwords.lib.client.AdWordsSession; import com.google.api.ads.adwords.lib.factory.AdWordsServicesInterface; import com.google.api.ads.adwords.lib.utils.examples.ArgumentNames; import com.google.api.ads.common.lib.auth.OfflineCredentials; import com.google.api.ads.common.lib.auth.OfflineCredentials.Api; import com.google.api.ads.common.lib.conf.ConfigurationLoadException; import com.google.api.ads.common.lib.exception.OAuthException; import com.google.api.ads.common.lib.exception.ValidationException; import com.google.api.ads.common.lib.utils.examples.CodeSampleParams; import com.google.api.client.auth.oauth2.Credential; import java.rmi.RemoteException; import java.util.List; /** * This example adds a shopping campaign. * * <p>Credentials and properties in {@code fromFile()} are pulled from the * "ads.properties" file. See README for more info. */ public class AddShoppingCampaign { private static class AddShoppingCampaignParams extends CodeSampleParams { @Parameter(names = ArgumentNames.BUDGET_ID, required = true) private Long budgetId; @Parameter(names = ArgumentNames.MERCHANT_ID, required = true) private Long merchantId; @Parameter(names = ArgumentNames.CREATE_DEFAULT_PARTITION, required = true, arity = 1, description = "If set to true, a default partition will be created. If running the" + " AddProductPartitionTree.java example right after this example, make sure this stays" + " set to false.") private boolean createDefaultPartition; } public static void main(String[] args) { AdWordsSession session; try { // Generate a refreshable OAuth2 credential. Credential oAuth2Credential = new OfflineCredentials.Builder() .forApi(Api.ADWORDS) .fromFile() .build() .generateCredential(); // Construct an AdWordsSession. session = new AdWordsSession.Builder().fromFile().withOAuth2Credential(oAuth2Credential).build(); } catch (ConfigurationLoadException cle) { System.err.printf( "Failed to load configuration from the %s file. Exception: %s%n", DEFAULT_CONFIGURATION_FILENAME, cle); return; } catch (ValidationException ve) { System.err.printf( "Invalid configuration in the %s file. Exception: %s%n", DEFAULT_CONFIGURATION_FILENAME, ve); return; } catch (OAuthException oe) { System.err.printf( "Failed to create OAuth credentials. Check OAuth settings in the %s file. " + "Exception: %s%n", DEFAULT_CONFIGURATION_FILENAME, oe); return; } AdWordsServicesInterface adWordsServices = AdWordsServices.getInstance(); AddShoppingCampaignParams params = new AddShoppingCampaignParams(); if (!params.parseArguments(args)) { // Either pass the required parameters for this example on the command line, or insert them // into the code here. See the parameter class definition above for descriptions. params.budgetId = Long.parseLong("INSERT_BUDGET_ID_HERE"); params.merchantId = Long.parseLong("INSERT_MERCHANT_ID_HERE"); params.createDefaultPartition = false; } try { runExample(adWordsServices, session, params.budgetId, params.merchantId, params.createDefaultPartition); } catch (ApiException apiException) { // ApiException is the base class for most exceptions thrown by an API request. Instances // of this exception have a message and a collection of ApiErrors that indicate the // type and underlying cause of the exception. Every exception object in the adwords.axis // packages will return a meaningful value from toString // // ApiException extends RemoteException, so this catch block must appear before the // catch block for RemoteException. System.err.println("Request failed due to ApiException. Underlying ApiErrors:"); if (apiException.getErrors() != null) { int i = 0; for (ApiError apiError : apiException.getErrors()) { System.err.printf(" Error %d: %s%n", i++, apiError); } } } catch (RemoteException re) { System.err.printf( "Request failed unexpectedly due to RemoteException: %s%n", re); } } /** * Runs the example. * * @param adWordsServices the services factory. * @param session the session. * @param budgetId the budget ID to use for the new campaign. * @param merchantId the Merchant Center ID for the new campaign. * @param createDefaultPartition if true, a default product partition for all products will be * created. * @throws ApiException if the API request failed with one or more service errors. * @throws RemoteException if the API request failed due to other errors. */ public static void runExample( AdWordsServicesInterface adWordsServices, AdWordsSession session, Long budgetId, Long merchantId, boolean createDefaultPartition) throws RemoteException { // Get the CampaignService CampaignServiceInterface campaignService = adWordsServices.get(session, CampaignServiceInterface.class); // Create campaign. Campaign campaign = new Campaign(); campaign.setName("Shopping campaign #" + System.currentTimeMillis()); // The advertisingChannelType is what makes this a Shopping campaign campaign.setAdvertisingChannelType(AdvertisingChannelType.SHOPPING); // Recommendation: Set the campaign to PAUSED when creating it to prevent // the ads from immediately serving. Set to ENABLED once you've added // targeting and the ads are ready to serve. campaign.setStatus(CampaignStatus.PAUSED); // Set shared budget (required). Budget budget = new Budget(); budget.setBudgetId(budgetId); campaign.setBudget(budget); // Set bidding strategy (required). BiddingStrategyConfiguration biddingStrategyConfiguration = new BiddingStrategyConfiguration(); biddingStrategyConfiguration.setBiddingStrategyType(BiddingStrategyType.MANUAL_CPC); campaign.setBiddingStrategyConfiguration(biddingStrategyConfiguration); // All Shopping campaigns need a ShoppingSetting. ShoppingSetting shoppingSetting = new ShoppingSetting(); shoppingSetting.setSalesCountry("US"); shoppingSetting.setCampaignPriority(0); shoppingSetting.setMerchantId(merchantId); // Set to 'true' to enable Local Inventory Ads in your campaign. shoppingSetting.setEnableLocal(true); campaign.setSettings(new Setting[] {shoppingSetting}); // Create operation. CampaignOperation campaignOperation = new CampaignOperation(); campaignOperation.setOperand(campaign); campaignOperation.setOperator(Operator.ADD); // Make the mutate request. CampaignReturnValue campaignAddResult = campaignService.mutate(new CampaignOperation[] {campaignOperation}); // Display result. campaign = campaignAddResult.getValue(0); System.out.printf("Campaign with name '%s' and ID %d was added.%n", campaign.getName(), campaign.getId()); // Get the AdGroupService. AdGroupServiceInterface adGroupService = adWordsServices.get(session, AdGroupServiceInterface.class); // Create ad group. AdGroup adGroup = new AdGroup(); adGroup.setCampaignId(campaign.getId()); adGroup.setName("Ad Group #" + System.currentTimeMillis()); // Create operation. AdGroupOperation adGroupOperation = new AdGroupOperation(); adGroupOperation.setOperand(adGroup); adGroupOperation.setOperator(Operator.ADD); // Make the mutate request. AdGroupReturnValue adGroupAddResult = adGroupService.mutate(new AdGroupOperation[] {adGroupOperation}); // Display result. adGroup = adGroupAddResult.getValue(0); System.out.printf("Ad group with name '%s' and ID %d was added.%n", adGroup.getName(), adGroup.getId()); // Create product ad. AdGroupAdServiceInterface adGroupAdService = adWordsServices.get(session, AdGroupAdServiceInterface.class); ProductAd productAd = new ProductAd(); // Create ad group ad. AdGroupAd adGroupAd = new AdGroupAd(); adGroupAd.setAdGroupId(adGroup.getId()); adGroupAd.setAd(productAd); // Create operation. AdGroupAdOperation adGroupAdOperation = new AdGroupAdOperation(); adGroupAdOperation.setOperand(adGroupAd); adGroupAdOperation.setOperator(Operator.ADD); // Make the mutate request. AdGroupAdReturnValue adGroupAdAddResult = adGroupAdService.mutate(new AdGroupAdOperation[] {adGroupAdOperation}); // Display result. adGroupAd = adGroupAdAddResult.getValue(0); System.out.printf("Product ad with ID %d was added.%n", adGroupAd.getAd().getId()); if (createDefaultPartition) { // Create an ad group criterion for 'All products' using the ProductPartitionTree utility. ProductPartitionTree productPartitionTree = ProductPartitionTree.createAdGroupTree(adWordsServices, session, adGroup.getId()); productPartitionTree .getRoot() .asBiddableUnit() .setBid(500000L); List<AdGroupCriterionOperation> mutateOperations = productPartitionTree.getMutateOperations(); // Make the mutate request. AdGroupCriterionServiceInterface adGroupCriterionService = adWordsServices.get(session, AdGroupCriterionServiceInterface.class); AdGroupCriterionReturnValue adGroupCriterionResult = adGroupCriterionService.mutate( mutateOperations.toArray(new AdGroupCriterionOperation[0])); // Display result. for (AdGroupCriterion adGroupCriterion : adGroupCriterionResult.getValue()) { System.out.printf( "Ad group criterion with ID %d in ad group with ID %d was added.%n", adGroupCriterion.getCriterion().getId(), adGroupCriterion.getAdGroupId()); } } } }
Add a Smart Shopping campaign
// Copyright 2018 Google LLC // // 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 // // https://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 adwords.axis.v201809.shoppingcampaigns; import static com.google.api.ads.common.lib.utils.Builder.DEFAULT_CONFIGURATION_FILENAME; import com.beust.jcommander.Parameter; import com.google.api.ads.adwords.axis.factory.AdWordsServices; import com.google.api.ads.adwords.axis.utils.v201809.shopping.ProductPartitionTree; import com.google.api.ads.adwords.axis.v201809.cm.AdGroup; import com.google.api.ads.adwords.axis.v201809.cm.AdGroupAd; import com.google.api.ads.adwords.axis.v201809.cm.AdGroupAdOperation; import com.google.api.ads.adwords.axis.v201809.cm.AdGroupAdReturnValue; import com.google.api.ads.adwords.axis.v201809.cm.AdGroupAdServiceInterface; import com.google.api.ads.adwords.axis.v201809.cm.AdGroupCriterion; import com.google.api.ads.adwords.axis.v201809.cm.AdGroupCriterionOperation; import com.google.api.ads.adwords.axis.v201809.cm.AdGroupCriterionReturnValue; import com.google.api.ads.adwords.axis.v201809.cm.AdGroupCriterionServiceInterface; import com.google.api.ads.adwords.axis.v201809.cm.AdGroupOperation; import com.google.api.ads.adwords.axis.v201809.cm.AdGroupReturnValue; import com.google.api.ads.adwords.axis.v201809.cm.AdGroupServiceInterface; import com.google.api.ads.adwords.axis.v201809.cm.AdGroupType; import com.google.api.ads.adwords.axis.v201809.cm.AdvertisingChannelSubType; import com.google.api.ads.adwords.axis.v201809.cm.AdvertisingChannelType; import com.google.api.ads.adwords.axis.v201809.cm.ApiError; import com.google.api.ads.adwords.axis.v201809.cm.ApiException; import com.google.api.ads.adwords.axis.v201809.cm.BiddingStrategyConfiguration; import com.google.api.ads.adwords.axis.v201809.cm.BiddingStrategyType; import com.google.api.ads.adwords.axis.v201809.cm.Budget; import com.google.api.ads.adwords.axis.v201809.cm.BudgetBudgetDeliveryMethod; import com.google.api.ads.adwords.axis.v201809.cm.BudgetOperation; import com.google.api.ads.adwords.axis.v201809.cm.BudgetServiceInterface; import com.google.api.ads.adwords.axis.v201809.cm.Campaign; import com.google.api.ads.adwords.axis.v201809.cm.CampaignOperation; import com.google.api.ads.adwords.axis.v201809.cm.CampaignReturnValue; import com.google.api.ads.adwords.axis.v201809.cm.CampaignServiceInterface; import com.google.api.ads.adwords.axis.v201809.cm.CampaignStatus; import com.google.api.ads.adwords.axis.v201809.cm.GoalOptimizedShoppingAd; import com.google.api.ads.adwords.axis.v201809.cm.Money; import com.google.api.ads.adwords.axis.v201809.cm.Operator; import com.google.api.ads.adwords.axis.v201809.cm.Setting; import com.google.api.ads.adwords.axis.v201809.cm.ShoppingSetting; import com.google.api.ads.adwords.lib.client.AdWordsSession; import com.google.api.ads.adwords.lib.factory.AdWordsServicesInterface; import com.google.api.ads.adwords.lib.utils.examples.ArgumentNames; import com.google.api.ads.common.lib.auth.OfflineCredentials; import com.google.api.ads.common.lib.auth.OfflineCredentials.Api; import com.google.api.ads.common.lib.conf.ConfigurationLoadException; import com.google.api.ads.common.lib.exception.OAuthException; import com.google.api.ads.common.lib.exception.ValidationException; import com.google.api.ads.common.lib.utils.examples.CodeSampleParams; import com.google.api.client.auth.oauth2.Credential; import java.rmi.RemoteException; import java.util.List; /** * This example adds a Smart Shopping campaign with an ad group and ad group ad. * * <p>Credentials and properties in {@code fromFile()} are pulled from the "ads.properties" file. * See README for more info. */ public class AddSmartShoppingAd { private static class AddSmartShoppingAdParams extends CodeSampleParams { @Parameter(names = ArgumentNames.MERCHANT_ID, required = true) private Long merchantId; @Parameter( names = ArgumentNames.CREATE_DEFAULT_PARTITION, required = true, arity = 1, description = "If set to true, a default partition will be created. If running the" + " AddProductPartitionTree.java example right after this example, make sure this" + " stays set to false.") private boolean createDefaultPartition; } public static void main(String[] args) { AdWordsSession session; try { // Generate a refreshable OAuth2 credential. Credential oAuth2Credential = new OfflineCredentials.Builder() .forApi(Api.ADWORDS) .fromFile() .build() .generateCredential(); // Construct an AdWordsSession. session = new AdWordsSession.Builder().fromFile().withOAuth2Credential(oAuth2Credential).build(); } catch (ConfigurationLoadException cle) { System.err.printf( "Failed to load configuration from the %s file. Exception: %s%n", DEFAULT_CONFIGURATION_FILENAME, cle); return; } catch (ValidationException ve) { System.err.printf( "Invalid configuration in the %s file. Exception: %s%n", DEFAULT_CONFIGURATION_FILENAME, ve); return; } catch (OAuthException oe) { System.err.printf( "Failed to create OAuth credentials. Check OAuth settings in the %s file. " + "Exception: %s%n", DEFAULT_CONFIGURATION_FILENAME, oe); return; } AdWordsServicesInterface adWordsServices = AdWordsServices.getInstance(); AddSmartShoppingAdParams params = new AddSmartShoppingAdParams(); if (!params.parseArguments(args)) { // Either pass the required parameters for this example on the command line, or insert them // into the code here. See the parameter class definition above for descriptions. params.merchantId = Long.parseLong("INSERT_MERCHANT_ID_HERE"); params.createDefaultPartition = false; } try { runExample(adWordsServices, session, params.merchantId, params.createDefaultPartition); } catch (ApiException apiException) { // ApiException is the base class for most exceptions thrown by an API request. Instances // of this exception have a message and a collection of ApiErrors that indicate the // type and underlying cause of the exception. Every exception object in the adwords.axis // packages will return a meaningful value from toString. // // ApiException extends RemoteException, so this catch block must appear before the // catch block for RemoteException. System.err.println("Request failed due to ApiException. Underlying ApiErrors:"); if (apiException.getErrors() != null) { int i = 0; for (ApiError apiError : apiException.getErrors()) { System.err.printf(" Error %d: %s%n", i++, apiError); } } } catch (RemoteException re) { System.err.printf("Request failed unexpectedly due to RemoteException: %s%n", re); } } /** * Runs the example. * * @param adWordsServices the services factory. * @param session the session. * @param merchantId the Merchant Center ID for the new campaign. * @param createDefaultPartition if true, a default product partition for all products will be * created. * @throws ApiException if the API request failed with one or more service errors. * @throws RemoteException if the API request failed due to other errors. */ public static void runExample( AdWordsServicesInterface adWordsServices, AdWordsSession session, long merchantId, boolean createDefaultPartition) throws RemoteException { Budget budget = createBudget(adWordsServices, session); Campaign campaign = createSmartShoppingCampaign(adWordsServices, session, budget.getBudgetId(), merchantId); AdGroup adGroup = createSmartShoppingAdGroup(adWordsServices, session, campaign.getId()); createSmartShoppingAd(adWordsServices, session, adGroup.getId()); if (createDefaultPartition) { createDefaultPartition(adWordsServices, session, adGroup.getId()); } } /** * Creates a non-shared budget for a Smart Shopping campaign. Smart Shopping campaigns support * only non-shared budgets. */ private static Budget createBudget( AdWordsServicesInterface adWordsServices, AdWordsSession session) throws RemoteException { BudgetServiceInterface budgetService = adWordsServices.get(session, BudgetServiceInterface.class); // Create a budget. Budget budget = new Budget(); budget.setName("Interplanetary Cruise #" + System.currentTimeMillis()); Money budgetAmount = new Money(); // This budget equals 50.00 units of your account's currency, e.g., // 50 USD if your currency is USD. budgetAmount.setMicroAmount(50_000_000L); budget.setAmount(budgetAmount); budget.setDeliveryMethod(BudgetBudgetDeliveryMethod.STANDARD); // Non-shared budgets are required for Smart Shopping campaigns. budget.setIsExplicitlyShared(false); // Create operation. BudgetOperation budgetOperation = new BudgetOperation(); budgetOperation.setOperand(budget); budgetOperation.setOperator(Operator.ADD); // Add the budget. Budget newBudget = budgetService.mutate(new BudgetOperation[] {budgetOperation}).getValue(0); System.out.printf( "Budget with name '%s' and ID %d was added.%n", newBudget.getName(), newBudget.getBudgetId()); return newBudget; } /** Creates a Smart Shopping campaign. */ private static Campaign createSmartShoppingCampaign( AdWordsServicesInterface adWordsServices, AdWordsSession session, Long budgetId, long merchantId) throws RemoteException { CampaignServiceInterface campaignService = adWordsServices.get(session, CampaignServiceInterface.class); // Create a campaign with required and optional settings. Campaign campaign = new Campaign(); campaign.setName("Smart Shopping campaign #" + System.currentTimeMillis()); // The advertisingChannelType is what makes this a Shopping campaign. campaign.setAdvertisingChannelType(AdvertisingChannelType.SHOPPING); // Sets the advertisingChannelSubType to SHOPPING_GOAL_OPTIMIZED_ADS to // make this a Smart Shopping campaign. campaign.setAdvertisingChannelSubType(AdvertisingChannelSubType.SHOPPING_GOAL_OPTIMIZED_ADS); // Recommendation: Set the campaign to PAUSED when creating it to stop // the ads from immediately serving. Set to ENABLED once you've added // targeting and the ads are ready to serve. campaign.setStatus(CampaignStatus.PAUSED); // Set a budget. Budget budget = new Budget(); budget.setBudgetId(budgetId); campaign.setBudget(budget); // Set bidding strategy. Only MAXIMIZE_CONVERSION_VALUE is supported. BiddingStrategyConfiguration biddingStrategyConfiguration = new BiddingStrategyConfiguration(); biddingStrategyConfiguration.setBiddingStrategyType( BiddingStrategyType.MAXIMIZE_CONVERSION_VALUE); campaign.setBiddingStrategyConfiguration(biddingStrategyConfiguration); // All Shopping campaigns need a ShoppingSetting. ShoppingSetting shoppingSetting = new ShoppingSetting(); shoppingSetting.setSalesCountry("US"); shoppingSetting.setMerchantId(merchantId); campaign.setSettings(new Setting[] {shoppingSetting}); // Create operation. CampaignOperation campaignOperation = new CampaignOperation(); campaignOperation.setOperand(campaign); campaignOperation.setOperator(Operator.ADD); // Make the mutate request. CampaignReturnValue campaignAddResult = campaignService.mutate(new CampaignOperation[] {campaignOperation}); // Display result. campaign = campaignAddResult.getValue(0); System.out.printf( "Smart Shopping campaign with name '%s' and ID %d was added.%n", campaign.getName(), campaign.getId()); return campaign; } /** * Creates a Smart Shopping ad group by setting the ad group type to SHOPPING_GOAL_OPTIMIZED_ADS. */ private static AdGroup createSmartShoppingAdGroup( AdWordsServicesInterface adWordsServices, AdWordsSession session, long campaignId) throws RemoteException { // Get the AdGroupService. AdGroupServiceInterface adGroupService = adWordsServices.get(session, AdGroupServiceInterface.class); // Create ad group. AdGroup adGroup = new AdGroup(); adGroup.setCampaignId(campaignId); adGroup.setName("Smart Shopping ad group #" + System.currentTimeMillis()); // Set the ad group type to SHOPPING_GOAL_OPTIMIZED_ADS. adGroup.setAdGroupType(AdGroupType.SHOPPING_GOAL_OPTIMIZED_ADS); // Create operation. AdGroupOperation adGroupOperation = new AdGroupOperation(); adGroupOperation.setOperand(adGroup); adGroupOperation.setOperator(Operator.ADD); // Make the mutate request. AdGroupReturnValue adGroupAddResult = adGroupService.mutate(new AdGroupOperation[] {adGroupOperation}); // Display result. adGroup = adGroupAddResult.getValue(0); System.out.printf( "Smart Shopping ad group with name '%s' and ID %d was added.%n", adGroup.getName(), adGroup.getId()); return adGroup; } /** Creates a Smart Shopping ad. */ private static void createSmartShoppingAd( AdWordsServicesInterface adWordsServices, AdWordsSession session, long adGroupId) throws RemoteException { AdGroupAdServiceInterface adGroupAdService = adWordsServices.get(session, AdGroupAdServiceInterface.class); // Create a Smart Shopping ad (Goal-optimized Shopping ad). GoalOptimizedShoppingAd smartShoppingAd = new GoalOptimizedShoppingAd(); // Create ad group ad. AdGroupAd adGroupAd = new AdGroupAd(); adGroupAd.setAdGroupId(adGroupId); adGroupAd.setAd(smartShoppingAd); // Create operation. AdGroupAdOperation adGroupAdOperation = new AdGroupAdOperation(); adGroupAdOperation.setOperand(adGroupAd); adGroupAdOperation.setOperator(Operator.ADD); // Make the mutate request. AdGroupAdReturnValue adGroupAdAddResult = adGroupAdService.mutate(new AdGroupAdOperation[] {adGroupAdOperation}); // Display result. adGroupAd = adGroupAdAddResult.getValue(0); System.out.printf("Smart Shopping ad with ID %d was added.%n", adGroupAd.getAd().getId()); } /** Creates a default product partition as an ad group criterion. */ private static void createDefaultPartition( AdWordsServicesInterface adWordsServices, AdWordsSession session, long adGroupId) throws RemoteException { // Create an ad group criterion for 'All products' using the ProductPartitionTree utility. ProductPartitionTree productPartitionTree = ProductPartitionTree.createAdGroupTree(adWordsServices, session, adGroupId); List<AdGroupCriterionOperation> mutateOperations = productPartitionTree.getMutateOperations(); // Make the mutate request. AdGroupCriterionServiceInterface adGroupCriterionService = adWordsServices.get(session, AdGroupCriterionServiceInterface.class); AdGroupCriterionReturnValue adGroupCriterionResult = adGroupCriterionService.mutate(mutateOperations.toArray(new AdGroupCriterionOperation[0])); // Display result. for (AdGroupCriterion adGroupCriterion : adGroupCriterionResult.getValue()) { System.out.printf( "Ad group criterion with ID %d in ad group with ID %d was added.%n", adGroupCriterion.getCriterion().getId(), adGroupCriterion.getAdGroupId()); } } }
Get the set of product bidding categories
// Copyright 2017 Google Inc. All Rights Reserved. // // 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 adwords.axis.v201809.shoppingcampaigns; import static com.google.api.ads.common.lib.utils.Builder.DEFAULT_CONFIGURATION_FILENAME; import com.google.api.ads.adwords.axis.factory.AdWordsServices; import com.google.api.ads.adwords.axis.utils.v201809.SelectorBuilder; import com.google.api.ads.adwords.axis.v201809.cm.ApiError; import com.google.api.ads.adwords.axis.v201809.cm.ApiException; import com.google.api.ads.adwords.axis.v201809.cm.ConstantDataServiceInterface; import com.google.api.ads.adwords.axis.v201809.cm.ProductBiddingCategoryData; import com.google.api.ads.adwords.axis.v201809.cm.Selector; import com.google.api.ads.adwords.lib.client.AdWordsSession; import com.google.api.ads.adwords.lib.factory.AdWordsServicesInterface; import com.google.api.ads.adwords.lib.selectorfields.v201809.cm.ConstantDataField; import com.google.api.ads.common.lib.auth.OfflineCredentials; import com.google.api.ads.common.lib.auth.OfflineCredentials.Api; import com.google.api.ads.common.lib.conf.ConfigurationLoadException; import com.google.api.ads.common.lib.exception.OAuthException; import com.google.api.ads.common.lib.exception.ValidationException; import com.google.api.client.auth.oauth2.Credential; import com.google.common.base.Preconditions; import com.google.common.collect.Maps; import java.rmi.RemoteException; import java.util.ArrayList; import java.util.List; import java.util.Map; /** * This example fetches the set of valid ProductBiddingCategories. * * <p>Credentials and properties in {@code fromFile()} are pulled from the * "ads.properties" file. See README for more info. */ public class GetProductCategoryTaxonomy { public static void main(String[] args) { AdWordsSession session; try { // Generate a refreshable OAuth2 credential. Credential oAuth2Credential = new OfflineCredentials.Builder() .forApi(Api.ADWORDS) .fromFile() .build() .generateCredential(); // Construct an AdWordsSession. session = new AdWordsSession.Builder().fromFile().withOAuth2Credential(oAuth2Credential).build(); } catch (ConfigurationLoadException cle) { System.err.printf( "Failed to load configuration from the %s file. Exception: %s%n", DEFAULT_CONFIGURATION_FILENAME, cle); return; } catch (ValidationException ve) { System.err.printf( "Invalid configuration in the %s file. Exception: %s%n", DEFAULT_CONFIGURATION_FILENAME, ve); return; } catch (OAuthException oe) { System.err.printf( "Failed to create OAuth credentials. Check OAuth settings in the %s file. " + "Exception: %s%n", DEFAULT_CONFIGURATION_FILENAME, oe); return; } AdWordsServicesInterface adWordsServices = AdWordsServices.getInstance(); try { runExample(adWordsServices, session); } catch (ApiException apiException) { // ApiException is the base class for most exceptions thrown by an API request. Instances // of this exception have a message and a collection of ApiErrors that indicate the // type and underlying cause of the exception. Every exception object in the adwords.axis // packages will return a meaningful value from toString // // ApiException extends RemoteException, so this catch block must appear before the // catch block for RemoteException. System.err.println("Request failed due to ApiException. Underlying ApiErrors:"); if (apiException.getErrors() != null) { int i = 0; for (ApiError apiError : apiException.getErrors()) { System.err.printf(" Error %d: %s%n", i++, apiError); } } } catch (RemoteException re) { System.err.printf( "Request failed unexpectedly due to RemoteException: %s%n", re); } } /** * Runs the example. * * @param adWordsServices the services factory. * @param session the session. * @throws ApiException if the API request failed with one or more service errors. * @throws RemoteException if the API request failed due to other errors. */ public static void runExample(AdWordsServicesInterface adWordsServices, AdWordsSession session) throws RemoteException { // Get the constant data service. ConstantDataServiceInterface constantDataService = adWordsServices.get(session, ConstantDataServiceInterface.class); Selector selector = new SelectorBuilder() .equals(ConstantDataField.Country, "US") .build(); ProductBiddingCategoryData[] results = constantDataService.getProductBiddingCategoryData(selector); // List of top level category nodes. List<CategoryNode> rootCategories = new ArrayList<>(); // Map of category ID to category node for all categories found in the results. Map<Long, CategoryNode> biddingCategories = Maps.newHashMap(); for (ProductBiddingCategoryData productBiddingCategoryData : results) { Long id = productBiddingCategoryData.getDimensionValue().getValue(); String name = productBiddingCategoryData.getDisplayValue(0).getValue(); CategoryNode node = biddingCategories.get(id); if (node == null) { node = new CategoryNode(id, name); biddingCategories.put(id, node); } else if (node.name == null) { // Ensure that the name attribute for the node is set. Name will be null for nodes added // to biddingCategories as a result of being a parentNode below. node.name = name; } if (productBiddingCategoryData.getParentDimensionValue() != null && productBiddingCategoryData.getParentDimensionValue().getValue() != null) { Long parentId = productBiddingCategoryData.getParentDimensionValue().getValue(); CategoryNode parentNode = biddingCategories.get(parentId); if (parentNode == null) { parentNode = new CategoryNode(parentId); biddingCategories.put(parentId, parentNode); } parentNode.children.add(node); } else { rootCategories.add(node); } } displayCategories(rootCategories, ""); } /** * Recursively prints out each category node and its children. * * @param categories the categories to print. * @param prefix the string to print at the beginning of each line of output. */ private static void displayCategories(List<CategoryNode> categories, String prefix) { for (CategoryNode category : categories) { System.out.printf("%s%s [%s]%n", prefix, category.name, category.id); displayCategories(category.children, String.format("%s%s > ", prefix, category.name)); } } /** * Node that tracks a product bidding category's id, name, and child nodes. */ private static class CategoryNode { final Long id; String name; final List<CategoryNode> children; /** * Constructor for categories first encountered as non-parent elements in the results. * * @param id the ID of the category * @param name the name of the category */ CategoryNode(Long id, String name) { this.children = new ArrayList<>(); this.id = Preconditions.checkNotNull(id); this.name = name; } /** * Constructor for categories first encountered as a parent category, in which case only the ID * is available. * * @param id the ID of the category */ CategoryNode(Long id) { this(id, null); } } }