3

I have a proto message:

syntax = "proto3";

import "google/protobuf/any.proto";

message Task {
    repeated google.protobuf.Any targets = 1;
    // ...
}

message Target {
    string name = 1;
    // ...
}

How should I add Target messages into Task.targets?

In official docs I've found info about how to assign value to a single Any type value, however in my case I have repeated Any field type.

Edit: Task.targets may contain different types of targets, that's why Any type is used. A single Target message is just for minimal reproducible example.

Prisacari Dmitrii
  • 1,985
  • 1
  • 23
  • 33

4 Answers4

3

Thanks @Justin Schoen. According to https://developers.google.com/protocol-buffers/docs/reference/java/com/google/protobuf/Any, you need to first create an Any object, then Pack a Target (or any other object type) before appending it to the repeated list.

from google.protobuf.any_pb2 import Any
task = Task()
target = Any()
target.Pack(Target())
task.targets.append(any)
matthewpark319
  • 1,214
  • 1
  • 14
  • 16
0

I have limited knowledge of the any type, but I would think it could be treated as if it were a repeated list of Target messages.

Python Code:

task_targets = []
task_targets.append(<insert_pb2_import>.Target(name='test'))
return <insert_pb2_import>.Task(targets=task_targets)
  • Simple test gives error: `TypeError: Parameter to MergeFrom() must be instance of same class: expected google.protobuf.Any got Target` – Prisacari Dmitrii Jun 03 '19 at 14:42
  • 1
    It looks like you need to initialize your `Any` array, and then use the `pack` method to add items to it. [check this out](https://developers.google.com/protocol-buffers/docs/reference/java/com/google/protobuf/Any) – Justin Schoen Jun 03 '19 at 14:53
0

After searching for an answer myself, I found this thread to be the most relevant so I'll post my solution here if it helps anyone (but in Java/Scala).

If you want

repeated google.protobuf.Any targets = 1;

and targets can be any value such as (string, bool, int, etc). This is how I did it in scala/java:

val task = Task.newBuilder()
    .addTargets(Any.pack(StringValue.of("iss")))
    .addTargets(Any.pack(Int32Value.of(25544)))
    .addTargets(Any.pack(DoubleValue.of(1004.882447947814)))
    .addTargets(Any.pack(DoubleValue.of(84.90917890132)))
    .addTargets(Any.pack(DoubleValue.of(14.620929684)))
    .addTargets(Any.pack(StringValue.of("kilometers")))
    .build()
Dharman
  • 30,962
  • 25
  • 85
  • 135
-1

After playing around some time I have decided to revise the solution that uses repeating Any. And here is an advice for those who got stuck in this same place: try to use specific types instead of Any.

A workaround for my situation is to create messages of types SpecificTargetSet1, SpecificTargetSet2, etc., that contain specific targets. The Task proto file would look like:

message Task {
    google.protobuf.Any target_set = 1;
}

Target set proto file:

message SpecificTargetSet1 {
    repeated SpecificTarget1 targets = 1;
}

And now a task could be created in such a way:

target = Target()
target.name = "Some name"

target_set = SpecificTargetSet1()
target_set.targets.append(target)

task = Task()
task.target_set.Pack(target_set)

I do not mark my answer as correct, as it is just a workaround.

Prisacari Dmitrii
  • 1,985
  • 1
  • 23
  • 33