Hey,

Don't know if it's the official way but we have written our own proto to
BigQuery converter which works pretty well.

public static TableRow convertEventToTableRow(TableRow tableRow,
Message event) {
    Map<Descriptors.FieldDescriptor, Object> fields = event.getAllFields();
    for (Descriptors.FieldDescriptor field : fields.keySet()) {
        tableRow = mapToBigQueryField(tableRow, field, fields.get(field));
    }

    return tableRow;
}

private static TableRow mapToBigQueryField(
        TableRow tableRow, Descriptors.FieldDescriptor field, Object value) {
    Descriptors.FieldDescriptor.JavaType fieldType = field.getJavaType();
    switch (fieldType) {
        case INT:
        case LONG:
        case FLOAT:
        case DOUBLE:
        case BOOLEAN:
            return tableRow.set(field.getName(), value);
        case BYTE_STRING:
            if (field.isRepeated()) {
                return tableRow.set(
                        field.getName(),
                        processRepeatedField(
                                value,
                                x ->
                                        Base64.getEncoder()
                                                .encodeToString(
                                                        ((ByteString)
x).toByteArray())));
            } else {
                return tableRow.set(
                        field.getName(),

Base64.getEncoder().encodeToString(((ByteString)
value).toByteArray()));
            }
        case ENUM:
            if (field.isRepeated()) {
                return tableRow.set(
                        field.getName(), processRepeatedField(value, x
-> x.toString()));
            } else {
                return tableRow.set(field.getName(), value.toString());
            }
        case STRING:
            if (isUUIDField(field.getName())) {
                if (field.isRepeated()) {
                    return tableRow.set(
                            field.getName(),
                            processRepeatedField(
                                    value, x ->
UUIDUtil.getBase64FromUUID((String) x)));
                } else {
                    return tableRow.set(
                            field.getName(),
UUIDUtil.getBase64FromUUID((String) value));
                }
            } else {
                return tableRow.set(field.getName(), value);
            }
        case MESSAGE:
            switch (field.getMessageType().getFullName()) {
                    // Map well known message types that we have a
specific mapping for.
                case "google.protobuf.Timestamp":
                    if (field.isRepeated()) {
                        return tableRow.set(
                                field.getName(),
                                processRepeatedField(
                                        value,
                                        x ->

com.google.cloud.Timestamp.fromProto(
                                                                (Timestamp) x)
                                                        .toString()));
                    } else {
                        return tableRow.set(
                                field.getName(),

com.google.cloud.Timestamp.fromProto((Timestamp) value)
                                        .toString());
                    }
                case "xxx.xxx.ExactNumber":
                    if (field.isRepeated()) {
                        return tableRow.set(
                                field.getName(),
                                processRepeatedField(
                                        value, x ->
NumberUtils.toString((ExactNumber) x)));
                    } else {
                        return tableRow.set(
                                field.getName(),
NumberUtils.toString((ExactNumber) value));
                    }
                case "google.protobuf.UInt64Value":
                    if (field.hasDefaultValue()) {
                        break;
                    } else if (value.equals(

com.google.protobuf.UInt64Value.getDefaultInstance())) {
                        value = 0;
                        return tableRow.set(field.getName(), value);
                    } else {
                        return tableRow.set(field.getName(),
((UInt64Value) value).getValue());
                    }
                case "google.protobuf.Int32Value":
                    if (field.hasDefaultValue()) {
                        break;
                    } else if (value.equals(

com.google.protobuf.Int32Value.getDefaultInstance())) {
                        value = 0;
                        return tableRow.set(field.getName(), value);
                    } else {
                        return tableRow.set(field.getName(),
((Int32Value) value).getValue());
                    }
                case "google.protobuf.DoubleValue":
                    if (field.hasDefaultValue()) {
                        break;
                    } else if (value.equals(

com.google.protobuf.DoubleValue.getDefaultInstance())) {
                        value = 0;
                        return tableRow.set(field.getName(), value);
                    } else {
                        return tableRow.set(field.getName(),
((DoubleValue) value).getValue());
                    }
                case "google.protobuf.FloatValue":
                    if (field.hasDefaultValue()) {
                        break;
                    } else if (value.equals(

com.google.protobuf.FloatValue.getDefaultInstance())) {
                        value = 0;

                        return tableRow.set(field.getName(), value);
                    } else {
                        return tableRow.set(field.getName(),
((FloatValue) value).getValue());
                    }
                case "google.protobuf.Int64Value":
                    if (field.hasDefaultValue()) {
                        break;
                    } else if (value.equals(

com.google.protobuf.Int64Value.getDefaultInstance())) {
                        value = 0;
                        return tableRow.set(field.getName(), value);
                    } else {
                        return tableRow.set(field.getName(),
((Int64Value) value).getValue());
                    }
                case "google.protobuf.UInt32Value":
                    if (field.hasDefaultValue()) {
                        break;
                    } else if (value.equals(

com.google.protobuf.UInt32Value.getDefaultInstance())) {
                        value = 0;
                        return tableRow.set(field.getName(), value);
                    } else {
                        return tableRow.set(field.getName(),
((UInt32Value) value).getValue());
                    }
                case "google.protobuf.BoolValue":
                    if (field.hasDefaultValue()) break;
                    else if
(value.equals(com.google.protobuf.BoolValue.getDefaultInstance())) {
                        value = false;
                        return tableRow.set(field.getName(), value);
                    } else {
                        return tableRow.set(field.getName(),
((BoolValue) value).getValue());
                    }
                case "google.protobuf.StringValue":
                    if (field.hasDefaultValue()) {
                        break;
                    } else if (value.equals(

com.google.protobuf.StringValue.getDefaultInstance())) {
                        value = "";
                        return tableRow.set(field.getName(), value);
                    } else if (isUUIDField(field.getName())) {
                        if (field.isRepeated()) {
                            return tableRow.set(
                                    field.getName(),
                                    processRepeatedField(
                                            value,
                                            x ->
                                                    UUIDUtil.getBase64FromUUID(

((StringValue) x).getValue())));
                        } else {
                            return tableRow.set(
                                    field.getName(),
                                    UUIDUtil.getBase64FromUUID(
                                            ((StringValue) value).getValue()));
                        }
                    } else if (field.isRepeated()) {
                        return tableRow.set(
                                field.getName(),
                                processRepeatedField(value, x ->
((StringValue) x).getValue()));
                    } else {
                        return tableRow.set(field.getName(),
((StringValue) value).getValue());
                    }
                case "google.protobuf.BytesValue":
                    if (field.hasDefaultValue()) {
                        break;
                    } else if (value.equals(

com.google.protobuf.BytesValue.getDefaultInstance())) {
                        value = ByteString.EMPTY;
                        return tableRow.set(field.getName(), value);
                    } else if (field.isRepeated()) {
                        return tableRow.set(
                                field.getName(),
                                processRepeatedField(
                                        value,
                                        x ->
                                                Base64.getEncoder()
                                                        .encodeToString(
                                                                ((BytesValue) x)

 .getValue()

 .toByteArray())));
                    } else {
                        return tableRow.set(
                                field.getName(),
                                Base64.getEncoder()
                                        .encodeToString(
                                                ((BytesValue)
value).getValue().toByteArray()));
                    }
                default:
                    if (field.isRepeated()) {
                        return tableRow.set(
                                field.getName(),
                                processRepeatedField(
                                        value,
                                        x ->
                                                convertEventToTableRow(
                                                        new
TableRow(), (Message) x)));
                    } else {
                        return tableRow.set(
                                field.getName(),
                                convertEventToTableRow(new TableRow(),
(Message) value));
                    }
            }
        default:
            throw new IllegalArgumentException(
                    field.getFullName() + " has an unsupported type "
+ field.getType());
    }
}


On Wed, Jul 8, 2020 at 4:40 PM Kaymak, Tobias <[email protected]>
wrote:

> As a workaround I am currently using the following code to generate a
> TableRow object from a Java Protobuf class - as I am facing a problem with
> Beam schemas (
> https://www.mail-archive.com/[email protected]/msg05799.html).
>
> It relies on the TableRowJsonCoder:
>
>       String json = JsonFormat.printer().omittingInsignificantWhitespace()
>           .preservingProtoFieldNames().print(article.toBuilder());
>       InputStream inputStream = new
> ByteArrayInputStream(json.getBytes(StandardCharsets.UTF_8));
>
>       TableRow tableRow = TableRowJsonCoder.of().decode(inputStream,
> Coder.Context.OUTER);
>
> However, the usage of Coder.Context is deprecated - I've tried to simply
> use the decode(), but that defaults to Context.NESTED.
>
> What is the correct way of doing this?
>
> Best,
> Tobi
>

Reply via email to