Máscaras de campo

Na API Google Ads, as atualizações são feitas usando uma máscara de campo. A máscara de campo (google.protobuf.FieldMask) contém uma lista de caminhos de campo em snake_case que você pretende mudar com a atualização. Todos os campos especificados que não estão na máscara de campo são ignorados, mesmo que sejam enviados ao servidor.

Utilitário FieldMasks

A maneira recomendada de gerar máscaras de campo na biblioteca de cliente Java é usar a classe utilitária FieldMasks integrada, que permite gerar máscaras de campo de um objeto modificado em vez de criá-las do zero.

Confira um exemplo de como atualizar uma campanha:

// Creates a Campaign object with the proper resource name and any other
// changes.
Campaign campaign =
    Campaign.newBuilder()
        .setResourceName(ResourceNames.campaign(customerId, campaignId))
        .setStatus(CampaignStatus.PAUSED)
        .build();

// Constructs an operation that updates the campaign, using the
// FieldMasks.allSetFieldsOf utility to derive the update mask. This mask tells
// the Google Ads API which attributes of the campaign you want to change.
CampaignOperation operation =
    CampaignOperation.newBuilder()
        .setUpdate(campaign)
        .setUpdateMask(FieldMasks.allSetFieldsOf(campaign))
        .build();

// Sends the operation in a mutate request.
MutateCampaignsResponse response =
    campaignServiceClient.mutateCampaigns(
        customerId.toString(), Collections.singletonList(operation));

Este exemplo primeiro cria um builder Campaign vazio e define o nome do recurso para que a API saiba qual campanha está sendo atualizada.

Em seguida, o exemplo chama FieldMasks.allSetFieldsOf() na campanha para produzir automaticamente uma máscara de campo que enumera todos os campos definidos. Você pode transmitir a máscara retornada diretamente para a chamada de atualização.

Se você precisar trabalhar com um objeto atual e atualizar alguns campos, use FieldMasks.compare() da seguinte maneira:

// Assumes existingCampaign was retrieved from a previous API call.

// Creates a new campaign based on the existing campaign and updates the
// campaign by setting its status to paused.
Campaign campaignToUpdate =
    existingCampaign.toBuilder()
        .setStatus(CampaignStatus.PAUSED)
        .build();

// Constructs an operation that updates the campaign, using the
// FieldMasks.compare utility to derive the update mask. This mask tells the
// Google Ads API which attributes of the campaign you want to change.
CampaignOperation operation =
    CampaignOperation.newBuilder()
        .setUpdate(campaignToUpdate)
        .setUpdateMask(FieldMasks.compare(existingCampaign, campaignToUpdate))
        .build();

// Sends the operation in a mutate request.
MutateCampaignsResponse response =
    campaignServiceClient.mutateCampaigns(
        customerId.toString(), Collections.singletonList(operation));

Para criar uma máscara de campo do zero, crie um builder FieldMask e adicione o nome snake_case de cada campo que você quer mudar:

FieldMask fieldMask =
    FieldMask.newBuilder()
        .addPaths("status")
        .addPaths("name")
        .build();

Atualizar campos de mensagens e subcampos

Os campos MESSAGE podem ter subcampos (como MaximizeConversions, que tem target_cpa_micros, cpc_bid_ceiling_micros e cpc_bid_floor_micros) ou não ter subcampos (como ManualCpm).

Campos de mensagem sem subcampos definidos

Ao atualizar um campo MESSAGE que não está definido com subcampos, use a utilidade FieldMasks para gerar uma máscara de campo, conforme descrito na seção anterior.

Campos de mensagem com subcampos definidos

Ao atualizar um campo MESSAGE que tem subcampos definidos sem definir explicitamente nenhum dos subcampos nessa mensagem, adicione manualmente cada um dos subcampos mutáveis MESSAGE ao FieldMask, semelhante à criação de uma máscara de campo do zero.

Um exemplo comum é atualizar a estratégia de lances de uma campanha (campo oneof campaign_bidding_strategy) sem definir nenhum dos campos na nova estratégia de lances. O exemplo a seguir demonstra como atualizar uma campanha para usar a estratégia de lances MaximizeConversions sem definir nenhum dos subcampos nela.

Nesse caso, usar apenas os métodos allSetFieldsOf() e compare() de FieldMasks não atinge a meta pretendida.

O exemplo a seguir gera uma máscara de campo que inclui maximize_conversions. No entanto, a API Google Ads não permite caminhos de mensagens de nível superior que tenham subcampos em uma máscara de atualização (para evitar a limpeza acidental de subcampos) e retorna um erro FieldMaskError.FIELD_HAS_SUBFIELDS.

// Creates a campaign with the proper resource name and an empty
// MaximizeConversions field.
Campaign campaign =
    Campaign.newBuilder()
        .setResourceName(ResourceNames.campaign(customerId, campaignId))
        .setMaximizeConversions(MaximizeConversions.newBuilder().build())
        .build();

// Constructs an operation using FieldMasks.allSetFieldsOf to derive the update
// mask. The field mask includes 'maximize_conversions', which produces a
// FieldMaskError.FIELD_HAS_SUBFIELDS error.
CampaignOperation operation =
    CampaignOperation.newBuilder()
        .setUpdate(campaign)
        .setUpdateMask(FieldMasks.allSetFieldsOf(campaign))
        .build();

// Sends the operation in a mutate request that results in a
// FieldMaskError.FIELD_HAS_SUBFIELDS error because empty MESSAGE fields with
// subfields cannot be included directly in a field mask.
MutateCampaignsResponse response =
    campaignServiceClient.mutateCampaigns(
        customerId.toString(), Collections.singletonList(operation));

O exemplo a seguir demonstra como atualizar corretamente uma campanha para usar a estratégia de lances MaximizeConversions sem definir nenhum dos subcampos dela. Saiba mais sobre como atribuir estratégias de lances padrão e de portfólio.

// Creates a Campaign object with the proper resource name.
Campaign campaign =
    Campaign.newBuilder()
        .setResourceName(ResourceNames.campaign(customerId, campaignId))
        .build();

// Creates a field mask from the campaign and adds the mutable subfield
// ('maximize_conversions.target_cpa_micros') on the MaximizeConversions
// bidding strategy to the field mask. Because this subfield is included in the
// field mask while excluded from the campaign object, the Google Ads API
// switches the campaign's bidding strategy oneof to MaximizeConversions with
// target_cpa_micros unset.
FieldMask fieldMask =
    FieldMasks.allSetFieldsOf(campaign).toBuilder()
        .addPaths("maximize_conversions.target_cpa_micros")
        .build();

// Creates an operation to update the campaign with the specified fields.
CampaignOperation operation =
    CampaignOperation.newBuilder()
        .setUpdate(campaign)
        .setUpdateMask(fieldMask)
        .build();

Limpar campos

Alguns campos podem ser limpos explicitamente. Assim como no exemplo anterior, você precisa adicionar explicitamente esses campos à máscara de campo, deixando-os não definidos no objeto de mensagem. Por exemplo, suponha que você tenha uma campanha que usa uma estratégia de lances MaximizeConversions e que o campo target_cpa_micros esteja definido com um valor maior que 0.

O código a seguir é executado, mas maximize_conversions.target_cpa_micros não será limpo conforme o esperado:

// Creates a campaign with the proper resource name and a MaximizeConversions
// object with target_cpa_micros set to 0L.
Campaign campaign =
    Campaign.newBuilder()
        .setResourceName(ResourceNames.campaign(customerId, campaignId))
        .setMaximizeConversions(
            MaximizeConversions.newBuilder().setTargetCpaMicros(0L).build())
        .setStatus(CampaignStatus.PAUSED)
        .build();

// Constructs an operation using FieldMasks.allSetFieldsOf to derive the
// update mask.
CampaignOperation operation =
    CampaignOperation.newBuilder()
        .setUpdate(campaign)
        .setUpdateMask(FieldMasks.allSetFieldsOf(campaign))
        .build();

// Sends the operation in a mutate request that does not clear the field
// cleanly.
MutateCampaignsResponse response =
    campaignServiceClient.mutateCampaigns(
        customerId.toString(), Collections.singletonList(operation));

O exemplo a seguir demonstra como limpar corretamente o campo target_cpa_micros na estratégia de lances MaximizeConversions.

// Creates a Campaign object with the proper resource name.
Campaign campaign =
    Campaign.newBuilder()
        .setResourceName(ResourceNames.campaign(customerId, campaignId))
        .build();

// Constructs a field mask from the campaign and adds the
// 'maximize_conversions.target_cpa_micros' field to the field mask, which
// clears this field from the bidding strategy without impacting any other
// fields on the bidding strategy.
FieldMask fieldMask =
    FieldMasks.allSetFieldsOf(campaign).toBuilder()
        .addPaths("maximize_conversions.target_cpa_micros")
        .build();

// Creates an operation to update the campaign with the specified field.
CampaignOperation operation =
    CampaignOperation.newBuilder()
        .setUpdate(campaign)
        .setUpdateMask(fieldMask)
        .build();