diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/AbstractResultSet.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/AbstractResultSet.java index 6ccb28900f9..40903b08afd 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/AbstractResultSet.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/AbstractResultSet.java @@ -36,8 +36,11 @@ import com.google.common.collect.ImmutableMap; import com.google.common.collect.Lists; import com.google.common.util.concurrent.Uninterruptibles; +import com.google.protobuf.AbstractMessage; import com.google.protobuf.ByteString; +import com.google.protobuf.InvalidProtocolBufferException; import com.google.protobuf.ListValue; +import com.google.protobuf.ProtocolMessageEnum; import com.google.protobuf.Value.KindCase; import com.google.spanner.v1.PartialResultSet; import com.google.spanner.v1.ResultSetMetadata; @@ -65,6 +68,7 @@ import java.util.concurrent.Executor; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.TimeUnit; +import java.util.function.Function; import java.util.logging.Level; import java.util.logging.Logger; import java.util.stream.Collectors; @@ -385,6 +389,10 @@ private Object writeReplace() { case JSON: builder.set(fieldName).to(Value.json((String) value)); break; + case PROTO: + builder.set(fieldName).to(Value.protoMessage((byte[]) value)); + case PROTO_ENUM: + builder.set(fieldName).to(Value.protoEnum((long) value)); case PG_JSONB: builder.set(fieldName).to(Value.pgJsonb((String) value)); break; @@ -490,6 +498,7 @@ private static Object decodeValue(Type fieldType, com.google.protobuf.Value prot checkType(fieldType, proto, KindCase.BOOL_VALUE); return proto.getBoolValue(); case INT64: + case PROTO_ENUM: checkType(fieldType, proto, KindCase.STRING_VALUE); return Long.parseLong(proto.getStringValue()); case FLOAT64: @@ -504,6 +513,7 @@ private static Object decodeValue(Type fieldType, com.google.protobuf.Value prot checkType(fieldType, proto, KindCase.STRING_VALUE); return proto.getStringValue(); case BYTES: + case PROTO: checkType(fieldType, proto, KindCase.STRING_VALUE); return ByteArray.fromBase64(proto.getStringValue()); case TIMESTAMP: @@ -655,6 +665,19 @@ public boolean isNull(int columnIndex) { return rowData.get(columnIndex) == null; } + @Override + public T getProtoMessageInternal(int columnIndex, T m) + throws InvalidProtocolBufferException { + return (T) m.toBuilder().mergeFrom(((ByteArray) rowData.get(columnIndex)).toByteArray()) + .build(); + } + + @Override + protected T getProtoEnumInternal( + int columnIndex, Function method) { + return (T) method.apply((int) getLongInternal(columnIndex)); + } + @Override protected boolean getBooleanInternal(int columnIndex) { return (Boolean) rowData.get(columnIndex); @@ -1368,6 +1391,18 @@ protected String getStringInternal(int columnIndex) { return currRow().getStringInternal(columnIndex); } + @Override + protected T getProtoMessageInternal(int columnIndex, T m) + throws InvalidProtocolBufferException { + return currRow().getProtoMessageInternal(columnIndex, m); + } + + @Override + protected T getProtoEnumInternal( + int columnIndex, Function method) { + return currRow().getProtoEnumInternal(columnIndex, method); + } + @Override protected String getJsonInternal(int columnIndex) { return currRow().getJsonInternal(columnIndex); diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/AbstractStructReader.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/AbstractStructReader.java index 1e897636245..f288b8fcb4a 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/AbstractStructReader.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/AbstractStructReader.java @@ -21,9 +21,13 @@ import com.google.cloud.ByteArray; import com.google.cloud.Date; import com.google.cloud.Timestamp; +import com.google.protobuf.AbstractMessage; +import com.google.protobuf.InvalidProtocolBufferException; +import com.google.protobuf.ProtocolMessageEnum; import java.math.BigDecimal; import java.util.Arrays; import java.util.List; +import java.util.function.Function; /** * Base class for assisting {@link StructReader} implementations. @@ -58,6 +62,12 @@ protected String getPgJsonbInternal(int columnIndex) { protected abstract Date getDateInternal(int columnIndex); + protected abstract T getProtoMessageInternal(int columnIndex, T m) + throws InvalidProtocolBufferException; + + protected abstract T getProtoEnumInternal( + int columnIndex, Function method); + protected Value getValueInternal(int columnIndex) { throw new UnsupportedOperationException("method should be overwritten"); } @@ -212,14 +222,16 @@ public String getPgJsonb(String columnName) { @Override public ByteArray getBytes(int columnIndex) { - checkNonNullOfType(columnIndex, Type.bytes(), columnIndex); + checkNonNullOfTypes(columnIndex, Arrays.asList(Type.bytes(), Type.proto()), columnIndex, + "BYTES, PROTO"); return getBytesInternal(columnIndex); } @Override public ByteArray getBytes(String columnName) { int columnIndex = getColumnIndex(columnName); - checkNonNullOfType(columnIndex, Type.bytes(), columnName); + checkNonNullOfTypes(columnIndex, Arrays.asList(Type.bytes(), Type.proto()), columnName, + "BYTES, PROTO"); return getBytesInternal(columnIndex); } @@ -249,6 +261,36 @@ public Date getDate(String columnName) { return getDateInternal(columnIndex); } + @Override + public T getProtoEnum( + int columnIndex, Function method) { + checkNonNullOfType(columnIndex, Type.protoEnum(), columnIndex); + return getProtoEnumInternal(columnIndex, method); + } + + @Override + public T getProtoEnum( + String columnName, Function method) { + int columnIndex = getColumnIndex(columnName); + checkNonNullOfType(columnIndex, Type.proto(), columnName); + return getProtoEnumInternal(columnIndex, method); + } + + @Override + public T getProtoMessage(int columnIndex, T m) + throws InvalidProtocolBufferException { + checkNonNullOfType(columnIndex, Type.proto(), columnIndex); + return getProtoMessageInternal(columnIndex, m); + } + + @Override + public T getProtoMessage(String columnName, T m) + throws InvalidProtocolBufferException { + int columnIndex = getColumnIndex(columnName); + checkNonNullOfType(columnIndex, Type.proto(), columnName); + return getProtoMessageInternal(columnIndex, m); + } + @Override public Value getValue(int columnIndex) { checkNonNull(columnIndex, columnIndex); diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/ForwardingStructReader.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/ForwardingStructReader.java index 2a85006fa95..9fae33fcba8 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/ForwardingStructReader.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/ForwardingStructReader.java @@ -22,8 +22,12 @@ import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.base.Suppliers; +import com.google.protobuf.AbstractMessage; +import com.google.protobuf.InvalidProtocolBufferException; +import com.google.protobuf.ProtocolMessageEnum; import java.math.BigDecimal; import java.util.List; +import java.util.function.Function; /** Forwarding implements of StructReader */ public class ForwardingStructReader implements StructReader { @@ -382,6 +386,34 @@ public List getStructList(String columnName) { return delegate.get().getStructList(columnName); } + @Override + public T getProtoMessage(int columnIndex, T m) + throws InvalidProtocolBufferException { + checkValidState(); + return delegate.get().getProtoMessage(columnIndex, m); + } + + @Override + public T getProtoMessage(String columnName, T m) + throws InvalidProtocolBufferException { + checkValidState(); + return delegate.get().getProtoMessage(columnName, m); + } + + @Override + public T getProtoEnum( + int columnIndex, Function method) { + checkValidState(); + return delegate.get().getProtoEnum(columnIndex, method); + } + + @Override + public T getProtoEnum( + String columnName, Function method) { + checkValidState(); + return delegate.get().getProtoEnum(columnName, method); + } + @Override public Value getValue(int columnIndex) { checkValidState(); diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/ProtoEnumWrapper.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/ProtoEnumWrapper.java new file mode 100644 index 00000000000..2c965f75307 --- /dev/null +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/ProtoEnumWrapper.java @@ -0,0 +1,33 @@ +/* + * Copyright 2022 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 + * + * 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 com.google.cloud.spanner; + +import com.google.protobuf.ProtocolMessageEnum; + +public class ProtoEnumWrapper { + ProtocolMessageEnum protocolMessageEnum; + long enumValue; + + ProtoEnumWrapper(ProtocolMessageEnum protoEnum) { + this.protocolMessageEnum = protoEnum; + this.enumValue = protoEnum.getNumber(); + } + + ProtoEnumWrapper(long val) { + this.enumValue = val; + } +} diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/ProtoMessageWrapper.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/ProtoMessageWrapper.java new file mode 100644 index 00000000000..cb731d2a9a5 --- /dev/null +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/ProtoMessageWrapper.java @@ -0,0 +1,42 @@ +/* + * Copyright 2022 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 + * + * 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 com.google.cloud.spanner; + +import com.google.protobuf.AbstractMessage; +import java.util.Arrays; + +public class ProtoMessageWrapper { + AbstractMessage message; + byte[] serializedMessage; + + ProtoMessageWrapper(AbstractMessage m) { + this.message = m; + this.serializedMessage = m.toByteArray(); + } + + ProtoMessageWrapper(byte[] serializedMessage) { + this.serializedMessage = serializedMessage; + } + + @Override + public String toString() { + if (message != null) { + return message.toString(); + } + return Arrays.toString(serializedMessage); + } +} diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/ResultSets.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/ResultSets.java index 6eacd3208e2..ede1a1a835e 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/ResultSets.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/ResultSets.java @@ -29,9 +29,13 @@ import com.google.common.base.Supplier; import com.google.common.collect.Lists; import com.google.common.util.concurrent.ThreadFactoryBuilder; +import com.google.protobuf.AbstractMessage; +import com.google.protobuf.InvalidProtocolBufferException; +import com.google.protobuf.ProtocolMessageEnum; import com.google.spanner.v1.ResultSetStats; import java.math.BigDecimal; import java.util.List; +import java.util.function.Function; /** Utility methods for working with {@link com.google.cloud.spanner.ResultSet}. */ public final class ResultSets { @@ -293,6 +297,31 @@ public Date getDate(String columnName) { return getCurrentRowAsStruct().getDate(columnName); } + + @Override + public T getProtoMessage(int columnIndex, T m) + throws InvalidProtocolBufferException { + return getCurrentRowAsStruct().getProtoMessage(columnIndex, m); + } + + @Override + public T getProtoMessage(String columnName, T m) + throws InvalidProtocolBufferException { + return getCurrentRowAsStruct().getProtoMessage(columnName, m); + } + + @Override + public T getProtoEnum( + int columnIndex, Function method) { + return getCurrentRowAsStruct().getProtoEnum(columnIndex, method); + } + + @Override + public T getProtoEnum( + String columnName, Function method) { + return getCurrentRowAsStruct().getProtoEnum(columnName, method); + } + @Override public Value getValue(int columnIndex) { return getCurrentRowAsStruct().getValue(columnIndex); diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/Struct.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/Struct.java index 48c989d145e..10c5f204d71 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/Struct.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/Struct.java @@ -28,11 +28,15 @@ import com.google.common.primitives.Booleans; import com.google.common.primitives.Doubles; import com.google.common.primitives.Longs; +import com.google.protobuf.AbstractMessage; +import com.google.protobuf.InvalidProtocolBufferException; +import com.google.protobuf.ProtocolMessageEnum; import java.io.Serializable; import java.math.BigDecimal; import java.util.ArrayList; import java.util.List; import java.util.Objects; +import java.util.function.Function; import javax.annotation.concurrent.Immutable; /** @@ -217,6 +221,18 @@ protected Date getDateInternal(int columnIndex) { return values.get(columnIndex).getDate(); } + @Override + protected T getProtoMessageInternal(int columnIndex, T m) + throws InvalidProtocolBufferException { + return values.get(columnIndex).getProtoMessage(m); + } + + @Override + protected T getProtoEnumInternal( + int columnIndex, Function method) { + return values.get(columnIndex).getProtoEnum(method); + } + @Override protected Value getValueInternal(int columnIndex) { return values.get(columnIndex); @@ -354,6 +370,7 @@ private Object getAsObject(int columnIndex) { case BOOL: return getBooleanInternal(columnIndex); case INT64: + case PROTO_ENUM: return getLongInternal(columnIndex); case FLOAT64: return getDoubleInternal(columnIndex); @@ -368,6 +385,7 @@ private Object getAsObject(int columnIndex) { case PG_JSONB: return getPgJsonbInternal(columnIndex); case BYTES: + case PROTO: return getBytesInternal(columnIndex); case TIMESTAMP: return getTimestampInternal(columnIndex); diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/StructReader.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/StructReader.java index a96c95cb953..b5cee21cb99 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/StructReader.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/StructReader.java @@ -19,8 +19,12 @@ import com.google.cloud.ByteArray; import com.google.cloud.Date; import com.google.cloud.Timestamp; +import com.google.protobuf.AbstractMessage; +import com.google.protobuf.InvalidProtocolBufferException; +import com.google.protobuf.ProtocolMessageEnum; import java.math.BigDecimal; import java.util.List; +import java.util.function.Function; /** * A base interface for reading the fields of a {@code STRUCT}. The Cloud Spanner yields {@code @@ -51,6 +55,7 @@ * Struct} is an immutable implementation of {@code StructReader}. */ public interface StructReader { + /** * Returns the type of the underlying data. This will always be a {@code STRUCT} type, with fields * corresponding to the data's columns. For the result of a read or query, this will always match @@ -294,6 +299,18 @@ default List getPgJsonbList(String columnName) { /** Returns the value of a non-{@code NULL} column with type {@code Type.array(Type.date())}. */ List getDateList(String columnName); + T getProtoMessage(int columnIndex, T m) + throws InvalidProtocolBufferException; + + T getProtoMessage(String columnName, T m) + throws InvalidProtocolBufferException; + + T getProtoEnum( + int columnIndex, Function method); + + T getProtoEnum( + String columnName, Function method); + /** * Returns the value of a non-{@code NULL} column with type {@code Type.array(Type.struct(...))}. */ diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/Type.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/Type.java index 7ba6b9a41e4..a0c02de4338 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/Type.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/Type.java @@ -56,6 +56,8 @@ public final class Type implements Serializable { private static final Type TYPE_BYTES = new Type(Code.BYTES, null, null); private static final Type TYPE_TIMESTAMP = new Type(Code.TIMESTAMP, null, null); private static final Type TYPE_DATE = new Type(Code.DATE, null, null); + private static final Type TYPE_PROTO = new Type(Code.PROTO, null, null); + private static final Type TYPE_PROTO_ENUM = new Type(Code.PROTO_ENUM, null, null); private static final Type TYPE_ARRAY_BOOL = new Type(Code.ARRAY, TYPE_BOOL, null); private static final Type TYPE_ARRAY_INT64 = new Type(Code.ARRAY, TYPE_INT64, null); private static final Type TYPE_ARRAY_FLOAT64 = new Type(Code.ARRAY, TYPE_FLOAT64, null); @@ -64,6 +66,8 @@ public final class Type implements Serializable { private static final Type TYPE_ARRAY_STRING = new Type(Code.ARRAY, TYPE_STRING, null); private static final Type TYPE_ARRAY_JSON = new Type(Code.ARRAY, TYPE_JSON, null); private static final Type TYPE_ARRAY_PG_JSONB = new Type(Code.ARRAY, TYPE_PG_JSONB, null); + private static final Type TYPE_ARRAY_PROTO = new Type(Code.ARRAY, TYPE_PROTO, null); + private static final Type TYPE_ARRAY_PROTO_ENUM = new Type(Code.ARRAY, TYPE_PROTO_ENUM, null); private static final Type TYPE_ARRAY_BYTES = new Type(Code.ARRAY, TYPE_BYTES, null); private static final Type TYPE_ARRAY_TIMESTAMP = new Type(Code.ARRAY, TYPE_TIMESTAMP, null); private static final Type TYPE_ARRAY_DATE = new Type(Code.ARRAY, TYPE_DATE, null); @@ -122,6 +126,14 @@ public static Type pgJsonb() { return TYPE_PG_JSONB; } + public static Type proto() { + return TYPE_PROTO; + } + + public static Type protoEnum() { + return TYPE_PROTO_ENUM; + } + /** Returns the descriptor for the {@code BYTES} type: a variable-length byte string. */ public static Type bytes() { return TYPE_BYTES; @@ -169,6 +181,10 @@ public static Type array(Type elementType) { return TYPE_ARRAY_TIMESTAMP; case DATE: return TYPE_ARRAY_DATE; + case PROTO: + return TYPE_ARRAY_PROTO; + case PROTO_ENUM: + return TYPE_ARRAY_PROTO_ENUM; default: return new Type(Code.ARRAY, elementType, null); } @@ -219,6 +235,8 @@ public enum Code { STRING(TypeCode.STRING), JSON(TypeCode.JSON), PG_JSONB(TypeCode.JSON, TypeAnnotationCode.PG_JSONB), + PROTO(TypeCode.PROTO), + PROTO_ENUM(TypeCode.ENUM), BYTES(TypeCode.BYTES), TIMESTAMP(TypeCode.TIMESTAMP), DATE(TypeCode.DATE), @@ -464,6 +482,10 @@ static Type fromProto(com.google.spanner.v1.Type proto) { return timestamp(); case DATE: return date(); + case PROTO: + return proto(); + case PROTO_ENUM: + return protoEnum(); case ARRAY: checkArgument( proto.hasArrayElementType(), diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/Value.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/Value.java index 3ec7b67f65b..795aab6f981 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/Value.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/Value.java @@ -24,8 +24,12 @@ import com.google.common.base.Preconditions; import com.google.common.collect.Iterables; import com.google.common.collect.Lists; +import com.google.common.io.BaseEncoding; +import com.google.protobuf.AbstractMessage; +import com.google.protobuf.InvalidProtocolBufferException; import com.google.protobuf.ListValue; import com.google.protobuf.NullValue; +import com.google.protobuf.ProtocolMessageEnum; import java.io.Serializable; import java.math.BigDecimal; import java.util.ArrayList; @@ -35,6 +39,7 @@ import java.util.Collections; import java.util.List; import java.util.Objects; +import java.util.function.Function; import java.util.stream.Collectors; import javax.annotation.Nullable; import javax.annotation.concurrent.Immutable; @@ -217,8 +222,24 @@ public static Value pgJsonb(@Nullable String v) { return new PgJsonbImpl(v == null, v); } + public static Value protoMessage(@Nullable AbstractMessage v) { + return new ProtoMessageImpl(v == null, v); + } + + public static Value protoMessage(@Nullable byte[] v) { + return new ProtoMessageImpl(v == null, v); + } + + public static Value protoEnum(@Nullable ProtocolMessageEnum v) { + return new ProtoEnumImpl(v == null, v); + } + + public static Value protoEnum(@Nullable long v) { + return new ProtoEnumImpl(false, v); + } + /** - * Returns a {@code BYTES} value. + * e Returns a {@code BYTES} value. Returns a {@code BYTES} value. * * @param v the value, which may be null */ @@ -541,6 +562,15 @@ public String getPgJsonb() { throw new UnsupportedOperationException("Not implemented"); } + public T getProtoMessage(T m) throws InvalidProtocolBufferException { + throw new UnsupportedOperationException("Not implemented"); + } + + public T getProtoEnum( + Function method) { + throw new UnsupportedOperationException("Not implemented"); + } + /** * Returns the value of a {@code BYTES}-typed instance. * @@ -851,6 +881,18 @@ public String getPgJsonb() { throw defaultGetter(Type.pgJsonb()); } + @Override + public T getProtoMessage(T m) + throws InvalidProtocolBufferException { + throw defaultGetter(Type.proto()); + } + + @Override + public T getProtoEnum( + Function method) { + throw defaultGetter(Type.protoEnum()); + } + @Override public ByteArray getBytes() { throw defaultGetter(Type.bytes()); @@ -1329,6 +1371,79 @@ void valueToString(StringBuilder b) { } } + private static class ProtoMessageImpl extends AbstractObjectValue { + private ProtoMessageImpl(boolean isNull, AbstractMessage value) { + super(isNull, Type.proto(), new ProtoMessageWrapper(value)); + } + + private ProtoMessageImpl(boolean isNull, byte[] serializedProtoArray) { + super(isNull, Type.proto(), new ProtoMessageWrapper(serializedProtoArray)); + } + + @Override + public ByteArray getBytes() { + checkType(Type.proto()); + checkNotNull(); + return ByteArray.copyFrom(value.serializedMessage); + } + + @Override + public T getProtoMessage(T m) + throws InvalidProtocolBufferException { + checkType(Type.proto()); + checkNotNull(); + return (T) m.toBuilder().mergeFrom(value.serializedMessage); + } + + @Override + com.google.protobuf.Value valueToProto() { + String base64EncodedString = BaseEncoding.base16().encode(value.serializedMessage); + return com.google.protobuf.Value.newBuilder().setStringValue(base64EncodedString).build(); + } + + @Override + void valueToString(StringBuilder b) { + b.append(value.toString()); + } + } + + private static class ProtoEnumImpl extends AbstractObjectValue { + private ProtoEnumImpl(boolean isNull, ProtocolMessageEnum protoEnum) { + super(isNull, Type.protoEnum(), new ProtoEnumWrapper(protoEnum)); + } + + private ProtoEnumImpl(boolean isNull, long enumValue) { + super(isNull, Type.protoEnum(), new ProtoEnumWrapper(enumValue)); + } + + @Override + public long getInt64() { + checkType(Type.protoEnum()); + checkNotNull(); + return value.enumValue; + } + + @Override + public T getProtoEnum( + Function method) { + checkType(Type.protoEnum()); + checkNotNull(); + return (T) method.apply((int) value.enumValue); + } + + @Override + void valueToString(StringBuilder b) { + b.append(value.toString()); + } + + @Override + com.google.protobuf.Value valueToProto() { + return com.google.protobuf.Value.newBuilder() + .setStringValue(Long.toString(value.enumValue)) + .build(); + } + } + private static class TimestampImpl extends AbstractObjectValue { private static final String COMMIT_TIMESTAMP_STRING = "spanner.commit_timestamp()"; @@ -1971,6 +2086,10 @@ private Value getValue(int fieldIndex) { return Value.date(value.getDate(fieldIndex)); case TIMESTAMP: return Value.timestamp(value.getTimestamp(fieldIndex)); + case PROTO: + return Value.protoMessage(value.getBytes(fieldIndex).toByteArray()); + case PROTO_ENUM: + return Value.protoEnum(value.getLong(fieldIndex)); case STRUCT: return Value.struct(value.getStruct(fieldIndex)); case ARRAY: diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/ValueBinder.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/ValueBinder.java index ec9e5a43d8f..a0967ff2ffb 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/ValueBinder.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/ValueBinder.java @@ -19,6 +19,8 @@ import com.google.cloud.ByteArray; import com.google.cloud.Date; import com.google.cloud.Timestamp; +import com.google.protobuf.AbstractMessage; +import com.google.protobuf.ProtocolMessageEnum; import java.math.BigDecimal; import javax.annotation.Nullable; @@ -95,6 +97,14 @@ public R to(@Nullable String value) { return handle(Value.string(value)); } + public R to(@Nullable AbstractMessage m) { + return handle(Value.protoMessage(m)); + } + + public R to(@Nullable ProtocolMessageEnum en) { + return handle(Value.protoEnum(en)); + } + /** Binds to {@code Value.bytes(value)} */ public R to(@Nullable ByteArray value) { return handle(Value.bytes(value)); diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/ChecksumResultSet.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/ChecksumResultSet.java index bb2f2fb817a..da0907d82c8 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/ChecksumResultSet.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/ChecksumResultSet.java @@ -225,6 +225,7 @@ public void funnel(Struct row, PrimitiveSink into) { funnelValue(type, row.getBoolean(i), into); break; case BYTES: + case PROTO: funnelValue(type, row.getBytes(i), into); break; case DATE: @@ -240,6 +241,7 @@ public void funnel(Struct row, PrimitiveSink into) { funnelValue(type, row.getString(i), into); break; case INT64: + case PROTO_ENUM: funnelValue(type, row.getLong(i), into); break; case STRING: diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/DirectExecuteResultSet.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/DirectExecuteResultSet.java index 8fb0bbe4409..d85c7255270 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/DirectExecuteResultSet.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/DirectExecuteResultSet.java @@ -25,9 +25,13 @@ import com.google.cloud.spanner.Type; import com.google.cloud.spanner.Value; import com.google.common.base.Preconditions; +import com.google.protobuf.AbstractMessage; +import com.google.protobuf.InvalidProtocolBufferException; +import com.google.protobuf.ProtocolMessageEnum; import com.google.spanner.v1.ResultSetStats; import java.math.BigDecimal; import java.util.List; +import java.util.function.Function; /** * {@link ResultSet} implementation used by the Spanner connection API to ensure that the query for @@ -431,6 +435,34 @@ public List getStructList(String columnName) { return delegate.getStructList(columnName); } + @Override + public T getProtoEnum( + int columnIndex, Function method) { + Preconditions.checkState(nextCalledByClient, MISSING_NEXT_CALL); + return delegate.getProtoEnum(columnIndex, method); + } + + @Override + public T getProtoEnum( + String columnName, Function method) { + Preconditions.checkState(nextCalledByClient, MISSING_NEXT_CALL); + return delegate.getProtoEnum(columnName, method); + } + + @Override + public T getProtoMessage(int columnIndex, T m) + throws InvalidProtocolBufferException { + Preconditions.checkState(nextCalledByClient, MISSING_NEXT_CALL); + return delegate.getProtoMessage(columnIndex, m); + } + + @Override + public T getProtoMessage(String columnName, T m) + throws InvalidProtocolBufferException { + Preconditions.checkState(nextCalledByClient, MISSING_NEXT_CALL); + return delegate.getProtoMessage(columnName, m); + } + @Override public boolean equals(Object o) { if (!(o instanceof DirectExecuteResultSet)) { diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/ReplaceableForwardingResultSet.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/ReplaceableForwardingResultSet.java index cc9759a4870..0707c287fa9 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/ReplaceableForwardingResultSet.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/ReplaceableForwardingResultSet.java @@ -27,9 +27,13 @@ import com.google.cloud.spanner.Type; import com.google.cloud.spanner.Value; import com.google.common.base.Preconditions; +import com.google.protobuf.AbstractMessage; +import com.google.protobuf.InvalidProtocolBufferException; +import com.google.protobuf.ProtocolMessageEnum; import com.google.spanner.v1.ResultSetStats; import java.math.BigDecimal; import java.util.List; +import java.util.function.Function; /** * Forwarding implementation of {@link ResultSet} that forwards all calls to a delegate that can be @@ -435,4 +439,32 @@ public List getStructList(String columnName) { checkClosed(); return delegate.getStructList(columnName); } + + @Override + public T getProtoMessage(int columnIndex, T m) + throws InvalidProtocolBufferException { + checkClosed(); + return delegate.getProtoMessage(columnIndex, m); + } + + @Override + public T getProtoMessage(String columnName, T m) + throws InvalidProtocolBufferException { + checkClosed(); + return delegate.getProtoMessage(columnName, m); + } + + @Override + public T getProtoEnum( + int columnIndex, Function method) { + checkClosed(); + return delegate.getProtoEnum(columnIndex, method); + } + + @Override + public T getProtoEnum( + String columnName, Function method) { + checkClosed(); + return delegate.getProtoEnum(columnName, method); + } } diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/AbstractStructReaderTypesTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/AbstractStructReaderTypesTest.java index 1b6280a6369..e8a61c233e0 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/AbstractStructReaderTypesTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/AbstractStructReaderTypesTest.java @@ -27,6 +27,8 @@ import com.google.cloud.Date; import com.google.cloud.Timestamp; import com.google.common.base.Throwables; +import com.google.protobuf.AbstractMessage; +import com.google.protobuf.ProtocolMessageEnum; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.math.BigDecimal; @@ -34,6 +36,7 @@ import java.util.Collection; import java.util.Collections; import java.util.List; +import java.util.function.Function; import javax.annotation.Nullable; import org.junit.Before; import org.junit.Test; @@ -95,6 +98,17 @@ protected Date getDateInternal(int columnIndex) { return null; } + @Override + protected T getProtoMessageInternal(int columnIndex, T m) { + return null; + } + + @Override + protected T getProtoEnumInternal( + int columnIndex, Function method) { + return null; + } + @Override protected Value getValueInternal(int columnIndex) { return null; diff --git a/proto-google-cloud-spanner-v1/src/main/java/com/google/spanner/v1/Type.java b/proto-google-cloud-spanner-v1/src/main/java/com/google/spanner/v1/Type.java index 63f411de123..52ab5b34cc9 100644 --- a/proto-google-cloud-spanner-v1/src/main/java/com/google/spanner/v1/Type.java +++ b/proto-google-cloud-spanner-v1/src/main/java/com/google/spanner/v1/Type.java @@ -41,6 +41,7 @@ private Type(com.google.protobuf.GeneratedMessageV3.Builder builder) { private Type() { code_ = 0; typeAnnotation_ = 0; + protoTypeFqn_ = ""; } @java.lang.Override @@ -116,6 +117,13 @@ private Type( typeAnnotation_ = rawValue; break; } + case 42: + { + java.lang.String s = input.readStringRequireUtf8(); + + protoTypeFqn_ = s; + break; + } default: { if (!parseUnknownField(input, unknownFields, extensionRegistry, tag)) { @@ -332,6 +340,43 @@ public com.google.spanner.v1.TypeAnnotationCode getTypeAnnotation() { return result == null ? com.google.spanner.v1.TypeAnnotationCode.UNRECOGNIZED : result; } + public static final int PROTO_TYPE_FQN_FIELD_NUMBER = 5; + private volatile java.lang.Object protoTypeFqn_; + /** + * string proto_type_fqn = 5; + * + * @return The protoTypeFqn. + */ + @java.lang.Override + public java.lang.String getProtoTypeFqn() { + java.lang.Object ref = protoTypeFqn_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + protoTypeFqn_ = s; + return s; + } + } + /** + * string proto_type_fqn = 5; + * + * @return The bytes for protoTypeFqn. + */ + @java.lang.Override + public com.google.protobuf.ByteString getProtoTypeFqnBytes() { + java.lang.Object ref = protoTypeFqn_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8((java.lang.String) ref); + protoTypeFqn_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + private byte memoizedIsInitialized = -1; @java.lang.Override @@ -359,6 +404,9 @@ public void writeTo(com.google.protobuf.CodedOutputStream output) throws java.io != com.google.spanner.v1.TypeAnnotationCode.TYPE_ANNOTATION_CODE_UNSPECIFIED.getNumber()) { output.writeEnum(4, typeAnnotation_); } + if (!com.google.protobuf.GeneratedMessageV3.isStringEmpty(protoTypeFqn_)) { + com.google.protobuf.GeneratedMessageV3.writeString(output, 5, protoTypeFqn_); + } unknownFields.writeTo(output); } @@ -381,6 +429,9 @@ public int getSerializedSize() { != com.google.spanner.v1.TypeAnnotationCode.TYPE_ANNOTATION_CODE_UNSPECIFIED.getNumber()) { size += com.google.protobuf.CodedOutputStream.computeEnumSize(4, typeAnnotation_); } + if (!com.google.protobuf.GeneratedMessageV3.isStringEmpty(protoTypeFqn_)) { + size += com.google.protobuf.GeneratedMessageV3.computeStringSize(5, protoTypeFqn_); + } size += unknownFields.getSerializedSize(); memoizedSize = size; return size; @@ -406,6 +457,7 @@ public boolean equals(final java.lang.Object obj) { if (!getStructType().equals(other.getStructType())) return false; } if (typeAnnotation_ != other.typeAnnotation_) return false; + if (!getProtoTypeFqn().equals(other.getProtoTypeFqn())) return false; if (!unknownFields.equals(other.unknownFields)) return false; return true; } @@ -429,6 +481,8 @@ public int hashCode() { } hash = (37 * hash) + TYPE_ANNOTATION_FIELD_NUMBER; hash = (53 * hash) + typeAnnotation_; + hash = (37 * hash) + PROTO_TYPE_FQN_FIELD_NUMBER; + hash = (53 * hash) + getProtoTypeFqn().hashCode(); hash = (29 * hash) + unknownFields.hashCode(); memoizedHashCode = hash; return hash; @@ -588,6 +642,8 @@ public Builder clear() { } typeAnnotation_ = 0; + protoTypeFqn_ = ""; + return this; } @@ -625,6 +681,7 @@ public com.google.spanner.v1.Type buildPartial() { result.structType_ = structTypeBuilder_.build(); } result.typeAnnotation_ = typeAnnotation_; + result.protoTypeFqn_ = protoTypeFqn_; onBuilt(); return result; } @@ -686,6 +743,10 @@ public Builder mergeFrom(com.google.spanner.v1.Type other) { if (other.typeAnnotation_ != 0) { setTypeAnnotationValue(other.getTypeAnnotationValue()); } + if (!other.getProtoTypeFqn().isEmpty()) { + protoTypeFqn_ = other.protoTypeFqn_; + onChanged(); + } this.mergeUnknownFields(other.unknownFields); onChanged(); return this; @@ -1309,6 +1370,82 @@ public Builder clearTypeAnnotation() { return this; } + private java.lang.Object protoTypeFqn_ = ""; + /** + * string proto_type_fqn = 5; + * + * @return The protoTypeFqn. + */ + public java.lang.String getProtoTypeFqn() { + java.lang.Object ref = protoTypeFqn_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + protoTypeFqn_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + * string proto_type_fqn = 5; + * + * @return The bytes for protoTypeFqn. + */ + public com.google.protobuf.ByteString getProtoTypeFqnBytes() { + java.lang.Object ref = protoTypeFqn_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8((java.lang.String) ref); + protoTypeFqn_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + * string proto_type_fqn = 5; + * + * @param value The protoTypeFqn to set. + * @return This builder for chaining. + */ + public Builder setProtoTypeFqn(java.lang.String value) { + if (value == null) { + throw new NullPointerException(); + } + + protoTypeFqn_ = value; + onChanged(); + return this; + } + /** + * string proto_type_fqn = 5; + * + * @return This builder for chaining. + */ + public Builder clearProtoTypeFqn() { + + protoTypeFqn_ = getDefaultInstance().getProtoTypeFqn(); + onChanged(); + return this; + } + /** + * string proto_type_fqn = 5; + * + * @param value The bytes for protoTypeFqn to set. + * @return This builder for chaining. + */ + public Builder setProtoTypeFqnBytes(com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + checkByteStringIsUtf8(value); + + protoTypeFqn_ = value; + onChanged(); + return this; + } + @java.lang.Override public final Builder setUnknownFields(final com.google.protobuf.UnknownFieldSet unknownFields) { return super.setUnknownFields(unknownFields); diff --git a/proto-google-cloud-spanner-v1/src/main/java/com/google/spanner/v1/TypeCode.java b/proto-google-cloud-spanner-v1/src/main/java/com/google/spanner/v1/TypeCode.java index 4b6561e9def..7702f2257b4 100644 --- a/proto-google-cloud-spanner-v1/src/main/java/com/google/spanner/v1/TypeCode.java +++ b/proto-google-cloud-spanner-v1/src/main/java/com/google/spanner/v1/TypeCode.java @@ -177,6 +177,10 @@ public enum TypeCode implements com.google.protobuf.ProtocolMessageEnum { * JSON = 11; */ JSON(11), + /** PROTO = 13; */ + PROTO(13), + /** ENUM = 14; */ + ENUM(14), UNRECOGNIZED(-1), ; @@ -324,6 +328,10 @@ public enum TypeCode implements com.google.protobuf.ProtocolMessageEnum { * JSON = 11; */ public static final int JSON_VALUE = 11; + /** PROTO = 13; */ + public static final int PROTO_VALUE = 13; + /** ENUM = 14; */ + public static final int ENUM_VALUE = 14; public final int getNumber() { if (this == UNRECOGNIZED) { @@ -373,6 +381,10 @@ public static TypeCode forNumber(int value) { return NUMERIC; case 11: return JSON; + case 13: + return PROTO; + case 14: + return ENUM; default: return null; } diff --git a/proto-google-cloud-spanner-v1/src/main/java/com/google/spanner/v1/TypeOrBuilder.java b/proto-google-cloud-spanner-v1/src/main/java/com/google/spanner/v1/TypeOrBuilder.java index 4c78a470d6d..0c705016caf 100644 --- a/proto-google-cloud-spanner-v1/src/main/java/com/google/spanner/v1/TypeOrBuilder.java +++ b/proto-google-cloud-spanner-v1/src/main/java/com/google/spanner/v1/TypeOrBuilder.java @@ -158,4 +158,17 @@ public interface TypeOrBuilder * @return The typeAnnotation. */ com.google.spanner.v1.TypeAnnotationCode getTypeAnnotation(); + + /** + * string proto_type_fqn = 5; + * + * @return The protoTypeFqn. + */ + java.lang.String getProtoTypeFqn(); + /** + * string proto_type_fqn = 5; + * + * @return The bytes for protoTypeFqn. + */ + com.google.protobuf.ByteString getProtoTypeFqnBytes(); } diff --git a/proto-google-cloud-spanner-v1/src/main/java/com/google/spanner/v1/TypeProto.java b/proto-google-cloud-spanner-v1/src/main/java/com/google/spanner/v1/TypeProto.java index ebca4e75d38..63aa67d3fee 100644 --- a/proto-google-cloud-spanner-v1/src/main/java/com/google/spanner/v1/TypeProto.java +++ b/proto-google-cloud-spanner-v1/src/main/java/com/google/spanner/v1/TypeProto.java @@ -50,27 +50,28 @@ public static com.google.protobuf.Descriptors.FileDescriptor getDescriptor() { java.lang.String[] descriptorData = { "\n\034google/spanner/v1/type.proto\022\021google.s" + "panner.v1\032\037google/api/field_behavior.pro" - + "to\"\337\001\n\004Type\022.\n\004code\030\001 \001(\0162\033.google.spann" + + "to\"\367\001\n\004Type\022.\n\004code\030\001 \001(\0162\033.google.spann" + "er.v1.TypeCodeB\003\340A\002\0223\n\022array_element_typ" + "e\030\002 \001(\0132\027.google.spanner.v1.Type\0222\n\013stru" + "ct_type\030\003 \001(\0132\035.google.spanner.v1.Struct" + "Type\022>\n\017type_annotation\030\004 \001(\0162%.google.s" - + "panner.v1.TypeAnnotationCode\"\177\n\nStructTy" - + "pe\0223\n\006fields\030\001 \003(\0132#.google.spanner.v1.S" - + "tructType.Field\032<\n\005Field\022\014\n\004name\030\001 \001(\t\022%" - + "\n\004type\030\002 \001(\0132\027.google.spanner.v1.Type*\245\001" - + "\n\010TypeCode\022\031\n\025TYPE_CODE_UNSPECIFIED\020\000\022\010\n" - + "\004BOOL\020\001\022\t\n\005INT64\020\002\022\013\n\007FLOAT64\020\003\022\r\n\tTIMES" - + "TAMP\020\004\022\010\n\004DATE\020\005\022\n\n\006STRING\020\006\022\t\n\005BYTES\020\007\022" - + "\t\n\005ARRAY\020\010\022\n\n\006STRUCT\020\t\022\013\n\007NUMERIC\020\n\022\010\n\004J" - + "SON\020\013*X\n\022TypeAnnotationCode\022$\n TYPE_ANNO" - + "TATION_CODE_UNSPECIFIED\020\000\022\016\n\nPG_NUMERIC\020" - + "\002\022\014\n\010PG_JSONB\020\003B\257\001\n\025com.google.spanner.v" - + "1B\tTypeProtoP\001Z8google.golang.org/genpro" - + "to/googleapis/spanner/v1;spanner\252\002\027Googl" - + "e.Cloud.Spanner.V1\312\002\027Google\\Cloud\\Spanne" - + "r\\V1\352\002\032Google::Cloud::Spanner::V1b\006proto" - + "3" + + "panner.v1.TypeAnnotationCode\022\026\n\016proto_ty" + + "pe_fqn\030\005 \001(\t\"\177\n\nStructType\0223\n\006fields\030\001 \003" + + "(\0132#.google.spanner.v1.StructType.Field\032" + + "<\n\005Field\022\014\n\004name\030\001 \001(\t\022%\n\004type\030\002 \001(\0132\027.g" + + "oogle.spanner.v1.Type*\272\001\n\010TypeCode\022\031\n\025TY" + + "PE_CODE_UNSPECIFIED\020\000\022\010\n\004BOOL\020\001\022\t\n\005INT64" + + "\020\002\022\013\n\007FLOAT64\020\003\022\r\n\tTIMESTAMP\020\004\022\010\n\004DATE\020\005" + + "\022\n\n\006STRING\020\006\022\t\n\005BYTES\020\007\022\t\n\005ARRAY\020\010\022\n\n\006ST" + + "RUCT\020\t\022\013\n\007NUMERIC\020\n\022\010\n\004JSON\020\013\022\t\n\005PROTO\020\r" + + "\022\010\n\004ENUM\020\016*X\n\022TypeAnnotationCode\022$\n TYPE" + + "_ANNOTATION_CODE_UNSPECIFIED\020\000\022\016\n\nPG_NUM" + + "ERIC\020\002\022\014\n\010PG_JSONB\020\003B\257\001\n\025com.google.span" + + "ner.v1B\tTypeProtoP\001Z8google.golang.org/g" + + "enproto/googleapis/spanner/v1;spanner\252\002\027" + + "Google.Cloud.Spanner.V1\312\002\027Google\\Cloud\\S" + + "panner\\V1\352\002\032Google::Cloud::Spanner::V1b\006" + + "proto3" }; descriptor = com.google.protobuf.Descriptors.FileDescriptor.internalBuildGeneratedFileFrom( @@ -83,7 +84,7 @@ public static com.google.protobuf.Descriptors.FileDescriptor getDescriptor() { new com.google.protobuf.GeneratedMessageV3.FieldAccessorTable( internal_static_google_spanner_v1_Type_descriptor, new java.lang.String[] { - "Code", "ArrayElementType", "StructType", "TypeAnnotation", + "Code", "ArrayElementType", "StructType", "TypeAnnotation", "ProtoTypeFqn", }); internal_static_google_spanner_v1_StructType_descriptor = getDescriptor().getMessageTypes().get(1); diff --git a/proto-google-cloud-spanner-v1/src/main/proto/google/spanner/v1/type.proto b/proto-google-cloud-spanner-v1/src/main/proto/google/spanner/v1/type.proto index 712ec187fcc..162e9b5ae91 100644 --- a/proto-google-cloud-spanner-v1/src/main/proto/google/spanner/v1/type.proto +++ b/proto-google-cloud-spanner-v1/src/main/proto/google/spanner/v1/type.proto @@ -47,6 +47,8 @@ message Type { // typically is not needed to process the content of a value (it doesn't // affect serialization) and clients can ignore it on the read path. TypeAnnotationCode type_annotation = 4; + + string proto_type_fqn = 5; } // `StructType` defines the fields of a [STRUCT][google.spanner.v1.TypeCode.STRUCT] type. @@ -145,6 +147,9 @@ enum TypeCode { // preserved. // - JSON array elements will have their order preserved. JSON = 11; + + PROTO = 13; + ENUM = 14; } // `TypeAnnotationCode` is used as a part of [Type][google.spanner.v1.Type] to diff --git a/samples/snippets/src/main/java/com/example/spanner/protobuf/QueryProtoColumnSample.java b/samples/snippets/src/main/java/com/example/spanner/protobuf/QueryProtoColumnSample.java new file mode 100644 index 00000000000..fec008fae13 --- /dev/null +++ b/samples/snippets/src/main/java/com/example/spanner/protobuf/QueryProtoColumnSample.java @@ -0,0 +1,46 @@ +package com.example.spanner.protobuf; + +import com.example.spanner.protobuf.book.Book; +import com.example.spanner.protobuf.book.Genre; +import com.google.cloud.spanner.DatabaseClient; +import com.google.cloud.spanner.DatabaseId; +import com.google.cloud.spanner.ResultSet; +import com.google.cloud.spanner.Spanner; +import com.google.cloud.spanner.SpannerOptions; +import com.google.cloud.spanner.Statement; +import com.google.protobuf.InvalidProtocolBufferException; +import java.lang.reflect.InvocationTargetException; + +public class QueryProtoColumnSample { + static void queryProtoColumn() { + String projectId = "my-project"; + String instanceId = "my-instance"; + String databaseId = "my-database"; + + try (Spanner spanner = + SpannerOptions.newBuilder().setProjectId(projectId).build().getService()) { + DatabaseClient client = + spanner.getDatabaseClient(DatabaseId.of(projectId, instanceId, databaseId)); + queryProtoColumn(client); + } catch (InvalidProtocolBufferException e) { + e.printStackTrace(); + } + } + + static void queryProtoColumn(DatabaseClient client) throws InvalidProtocolBufferException { + Statement statement = + Statement.newBuilder("SELECT bookId, bookProto, genre \n" + "FROM Library").build(); + + try (ResultSet resultSet = client.singleUse().executeQuery(statement)) { + while (resultSet.next()) { + System.out.printf( + "bookId: %s, bookProto: %s, genre: %s %n", + resultSet.getLong("bookId"), + resultSet.getProtoMessage("bookProto", Book.getDefaultInstance()), + resultSet.getProtoEnum("genre", Genre::forNumber)); + } + } catch (InvalidProtocolBufferException e) { + e.printStackTrace(); + } + } +} diff --git a/samples/snippets/src/main/java/com/example/spanner/protobuf/UpdateProtoColumnSample.java b/samples/snippets/src/main/java/com/example/spanner/protobuf/UpdateProtoColumnSample.java new file mode 100644 index 00000000000..7ede67b1ce7 --- /dev/null +++ b/samples/snippets/src/main/java/com/example/spanner/protobuf/UpdateProtoColumnSample.java @@ -0,0 +1,48 @@ +package com.example.spanner.protobuf; + +import com.example.spanner.protobuf.book.Book; +import com.example.spanner.protobuf.book.Genre; +import com.google.cloud.spanner.DatabaseClient; +import com.google.cloud.spanner.DatabaseId; +import com.google.cloud.spanner.Mutation; +import com.google.cloud.spanner.Spanner; +import com.google.cloud.spanner.SpannerOptions; +import com.google.cloud.spanner.Value; +import com.google.common.collect.ImmutableList; + +public class UpdateProtoColumnSample { + static void updateProtoData() { + String projectId = "my-project"; + String instanceId = "my-instance"; + String databaseId = "my-database"; + + try (Spanner spanner = + SpannerOptions.newBuilder().setProjectId(projectId).build().getService()) { + DatabaseClient client = + spanner.getDatabaseClient(DatabaseId.of(projectId, instanceId, databaseId)); + updateProtoData(client); + } + } + + /* + * Assuming a table Library with two columns bookId & bookProto + * */ + static void updateProtoData(DatabaseClient client) { + Book bookProto = + Book.newBuilder() + .setAuthor("J.K. Rowling") + .setGenre(Genre.ROCK) + .setTitle("Harry Potter") + .build(); + client.write( + ImmutableList.of( + Mutation.newInsertOrUpdateBuilder("Library") + .set("bookId") + .to(4L) + .set("bookProto") + .to(Value.protoMessage(bookProto)) + .set("genre") + .to(Value.protoEnum(Genre.ROCK)) + .build())); + } +} diff --git a/samples/snippets/src/main/java/com/example/spanner/protobuf/book/Book.java b/samples/snippets/src/main/java/com/example/spanner/protobuf/book/Book.java new file mode 100644 index 00000000000..7fba64ced75 --- /dev/null +++ b/samples/snippets/src/main/java/com/example/spanner/protobuf/book/Book.java @@ -0,0 +1,856 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: book.proto + +package com.example.spanner.protobuf.book; + +/** + * Protobuf type {@code com.book.Book} + */ +public final class Book extends + com.google.protobuf.GeneratedMessageV3 implements + // @@protoc_insertion_point(message_implements:com.book.Book) + BookOrBuilder { + private static final long serialVersionUID = 0L; + // Use Book.newBuilder() to construct. + private Book(com.google.protobuf.GeneratedMessageV3.Builder builder) { + super(builder); + } + private Book() { + title_ = ""; + author_ = ""; + genre_ = 0; + } + + @java.lang.Override + @SuppressWarnings({"unused"}) + protected java.lang.Object newInstance( + UnusedPrivateParameter unused) { + return new Book(); + } + + @java.lang.Override + public final com.google.protobuf.UnknownFieldSet + getUnknownFields() { + return this.unknownFields; + } + private Book( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + this(); + if (extensionRegistry == null) { + throw new java.lang.NullPointerException(); + } + com.google.protobuf.UnknownFieldSet.Builder unknownFields = + com.google.protobuf.UnknownFieldSet.newBuilder(); + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + case 8: { + + isbn_ = input.readInt64(); + break; + } + case 18: { + java.lang.String s = input.readStringRequireUtf8(); + + title_ = s; + break; + } + case 26: { + java.lang.String s = input.readStringRequireUtf8(); + + author_ = s; + break; + } + case 32: { + int rawValue = input.readEnum(); + + genre_ = rawValue; + break; + } + default: { + if (!parseUnknownField( + input, unknownFields, extensionRegistry, tag)) { + done = true; + } + break; + } + } + } + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(this); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException( + e).setUnfinishedMessage(this); + } finally { + this.unknownFields = unknownFields.build(); + makeExtensionsImmutable(); + } + } + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return com.example.spanner.protobuf.book.BookProto.internal_static_com_book_Book_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable + internalGetFieldAccessorTable() { + return com.example.spanner.protobuf.book.BookProto.internal_static_com_book_Book_fieldAccessorTable + .ensureFieldAccessorsInitialized( + com.example.spanner.protobuf.book.Book.class, com.example.spanner.protobuf.book.Book.Builder.class); + } + + public static final int ISBN_FIELD_NUMBER = 1; + private long isbn_; + /** + * int64 isbn = 1; + * @return The isbn. + */ + @java.lang.Override + public long getIsbn() { + return isbn_; + } + + public static final int TITLE_FIELD_NUMBER = 2; + private volatile java.lang.Object title_; + /** + * string title = 2; + * @return The title. + */ + @java.lang.Override + public java.lang.String getTitle() { + java.lang.Object ref = title_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + title_ = s; + return s; + } + } + /** + * string title = 2; + * @return The bytes for title. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getTitleBytes() { + java.lang.Object ref = title_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + title_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int AUTHOR_FIELD_NUMBER = 3; + private volatile java.lang.Object author_; + /** + * string author = 3; + * @return The author. + */ + @java.lang.Override + public java.lang.String getAuthor() { + java.lang.Object ref = author_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + author_ = s; + return s; + } + } + /** + * string author = 3; + * @return The bytes for author. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getAuthorBytes() { + java.lang.Object ref = author_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + author_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int GENRE_FIELD_NUMBER = 4; + private int genre_; + /** + * .com.book.Genre genre = 4; + * @return The enum numeric value on the wire for genre. + */ + @java.lang.Override public int getGenreValue() { + return genre_; + } + /** + * .com.book.Genre genre = 4; + * @return The genre. + */ + @java.lang.Override public com.example.spanner.protobuf.book.Genre getGenre() { + @SuppressWarnings("deprecation") + com.example.spanner.protobuf.book.Genre result = com.example.spanner.protobuf.book.Genre.valueOf(genre_); + return result == null ? com.example.spanner.protobuf.book.Genre.UNRECOGNIZED : result; + } + + private byte memoizedIsInitialized = -1; + @java.lang.Override + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + memoizedIsInitialized = 1; + return true; + } + + @java.lang.Override + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + if (isbn_ != 0L) { + output.writeInt64(1, isbn_); + } + if (!getTitleBytes().isEmpty()) { + com.google.protobuf.GeneratedMessageV3.writeString(output, 2, title_); + } + if (!getAuthorBytes().isEmpty()) { + com.google.protobuf.GeneratedMessageV3.writeString(output, 3, author_); + } + if (genre_ != com.example.spanner.protobuf.book.Genre.BLUES.getNumber()) { + output.writeEnum(4, genre_); + } + unknownFields.writeTo(output); + } + + @java.lang.Override + public int getSerializedSize() { + int size = memoizedSize; + if (size != -1) return size; + + size = 0; + if (isbn_ != 0L) { + size += com.google.protobuf.CodedOutputStream + .computeInt64Size(1, isbn_); + } + if (!getTitleBytes().isEmpty()) { + size += com.google.protobuf.GeneratedMessageV3.computeStringSize(2, title_); + } + if (!getAuthorBytes().isEmpty()) { + size += com.google.protobuf.GeneratedMessageV3.computeStringSize(3, author_); + } + if (genre_ != com.example.spanner.protobuf.book.Genre.BLUES.getNumber()) { + size += com.google.protobuf.CodedOutputStream + .computeEnumSize(4, genre_); + } + size += unknownFields.getSerializedSize(); + memoizedSize = size; + return size; + } + + @java.lang.Override + public boolean equals(final java.lang.Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof com.example.spanner.protobuf.book.Book)) { + return super.equals(obj); + } + com.example.spanner.protobuf.book.Book other = (com.example.spanner.protobuf.book.Book) obj; + + if (getIsbn() + != other.getIsbn()) return false; + if (!getTitle() + .equals(other.getTitle())) return false; + if (!getAuthor() + .equals(other.getAuthor())) return false; + if (genre_ != other.genre_) return false; + if (!unknownFields.equals(other.unknownFields)) return false; + return true; + } + + @java.lang.Override + public int hashCode() { + if (memoizedHashCode != 0) { + return memoizedHashCode; + } + int hash = 41; + hash = (19 * hash) + getDescriptor().hashCode(); + hash = (37 * hash) + ISBN_FIELD_NUMBER; + hash = (53 * hash) + com.google.protobuf.Internal.hashLong( + getIsbn()); + hash = (37 * hash) + TITLE_FIELD_NUMBER; + hash = (53 * hash) + getTitle().hashCode(); + hash = (37 * hash) + AUTHOR_FIELD_NUMBER; + hash = (53 * hash) + getAuthor().hashCode(); + hash = (37 * hash) + GENRE_FIELD_NUMBER; + hash = (53 * hash) + genre_; + hash = (29 * hash) + unknownFields.hashCode(); + memoizedHashCode = hash; + return hash; + } + + public static com.example.spanner.protobuf.book.Book parseFrom( + java.nio.ByteBuffer data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.example.spanner.protobuf.book.Book parseFrom( + java.nio.ByteBuffer data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.example.spanner.protobuf.book.Book parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.example.spanner.protobuf.book.Book parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.example.spanner.protobuf.book.Book parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.example.spanner.protobuf.book.Book parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.example.spanner.protobuf.book.Book parseFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseWithIOException(PARSER, input); + } + public static com.example.spanner.protobuf.book.Book parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseWithIOException(PARSER, input, extensionRegistry); + } + public static com.example.spanner.protobuf.book.Book parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseDelimitedWithIOException(PARSER, input); + } + public static com.example.spanner.protobuf.book.Book parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseDelimitedWithIOException(PARSER, input, extensionRegistry); + } + public static com.example.spanner.protobuf.book.Book parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseWithIOException(PARSER, input); + } + public static com.example.spanner.protobuf.book.Book parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseWithIOException(PARSER, input, extensionRegistry); + } + + @java.lang.Override + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder() { + return DEFAULT_INSTANCE.toBuilder(); + } + public static Builder newBuilder(com.example.spanner.protobuf.book.Book prototype) { + return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); + } + @java.lang.Override + public Builder toBuilder() { + return this == DEFAULT_INSTANCE + ? new Builder() : new Builder().mergeFrom(this); + } + + @java.lang.Override + protected Builder newBuilderForType( + com.google.protobuf.GeneratedMessageV3.BuilderParent parent) { + Builder builder = new Builder(parent); + return builder; + } + /** + * Protobuf type {@code com.book.Book} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessageV3.Builder implements + // @@protoc_insertion_point(builder_implements:com.book.Book) + com.example.spanner.protobuf.book.BookOrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return com.example.spanner.protobuf.book.BookProto.internal_static_com_book_Book_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable + internalGetFieldAccessorTable() { + return com.example.spanner.protobuf.book.BookProto.internal_static_com_book_Book_fieldAccessorTable + .ensureFieldAccessorsInitialized( + com.example.spanner.protobuf.book.Book.class, com.example.spanner.protobuf.book.Book.Builder.class); + } + + // Construct using com.example.spanner.protobuf.book.Book.newBuilder() + private Builder() { + maybeForceBuilderInitialization(); + } + + private Builder( + com.google.protobuf.GeneratedMessageV3.BuilderParent parent) { + super(parent); + maybeForceBuilderInitialization(); + } + private void maybeForceBuilderInitialization() { + if (com.google.protobuf.GeneratedMessageV3 + .alwaysUseFieldBuilders) { + } + } + @java.lang.Override + public Builder clear() { + super.clear(); + isbn_ = 0L; + + title_ = ""; + + author_ = ""; + + genre_ = 0; + + return this; + } + + @java.lang.Override + public com.google.protobuf.Descriptors.Descriptor + getDescriptorForType() { + return com.example.spanner.protobuf.book.BookProto.internal_static_com_book_Book_descriptor; + } + + @java.lang.Override + public com.example.spanner.protobuf.book.Book getDefaultInstanceForType() { + return com.example.spanner.protobuf.book.Book.getDefaultInstance(); + } + + @java.lang.Override + public com.example.spanner.protobuf.book.Book build() { + com.example.spanner.protobuf.book.Book result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + @java.lang.Override + public com.example.spanner.protobuf.book.Book buildPartial() { + com.example.spanner.protobuf.book.Book result = new com.example.spanner.protobuf.book.Book(this); + result.isbn_ = isbn_; + result.title_ = title_; + result.author_ = author_; + result.genre_ = genre_; + onBuilt(); + return result; + } + + @java.lang.Override + public Builder clone() { + return super.clone(); + } + @java.lang.Override + public Builder setField( + com.google.protobuf.Descriptors.FieldDescriptor field, + java.lang.Object value) { + return super.setField(field, value); + } + @java.lang.Override + public Builder clearField( + com.google.protobuf.Descriptors.FieldDescriptor field) { + return super.clearField(field); + } + @java.lang.Override + public Builder clearOneof( + com.google.protobuf.Descriptors.OneofDescriptor oneof) { + return super.clearOneof(oneof); + } + @java.lang.Override + public Builder setRepeatedField( + com.google.protobuf.Descriptors.FieldDescriptor field, + int index, java.lang.Object value) { + return super.setRepeatedField(field, index, value); + } + @java.lang.Override + public Builder addRepeatedField( + com.google.protobuf.Descriptors.FieldDescriptor field, + java.lang.Object value) { + return super.addRepeatedField(field, value); + } + @java.lang.Override + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof com.example.spanner.protobuf.book.Book) { + return mergeFrom((com.example.spanner.protobuf.book.Book)other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(com.example.spanner.protobuf.book.Book other) { + if (other == com.example.spanner.protobuf.book.Book.getDefaultInstance()) return this; + if (other.getIsbn() != 0L) { + setIsbn(other.getIsbn()); + } + if (!other.getTitle().isEmpty()) { + title_ = other.title_; + onChanged(); + } + if (!other.getAuthor().isEmpty()) { + author_ = other.author_; + onChanged(); + } + if (other.genre_ != 0) { + setGenreValue(other.getGenreValue()); + } + this.mergeUnknownFields(other.unknownFields); + onChanged(); + return this; + } + + @java.lang.Override + public final boolean isInitialized() { + return true; + } + + @java.lang.Override + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + com.example.spanner.protobuf.book.Book parsedMessage = null; + try { + parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + parsedMessage = (com.example.spanner.protobuf.book.Book) e.getUnfinishedMessage(); + throw e.unwrapIOException(); + } finally { + if (parsedMessage != null) { + mergeFrom(parsedMessage); + } + } + return this; + } + + private long isbn_ ; + /** + * int64 isbn = 1; + * @return The isbn. + */ + @java.lang.Override + public long getIsbn() { + return isbn_; + } + /** + * int64 isbn = 1; + * @param value The isbn to set. + * @return This builder for chaining. + */ + public Builder setIsbn(long value) { + + isbn_ = value; + onChanged(); + return this; + } + /** + * int64 isbn = 1; + * @return This builder for chaining. + */ + public Builder clearIsbn() { + + isbn_ = 0L; + onChanged(); + return this; + } + + private java.lang.Object title_ = ""; + /** + * string title = 2; + * @return The title. + */ + public java.lang.String getTitle() { + java.lang.Object ref = title_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + title_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + * string title = 2; + * @return The bytes for title. + */ + public com.google.protobuf.ByteString + getTitleBytes() { + java.lang.Object ref = title_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + title_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + * string title = 2; + * @param value The title to set. + * @return This builder for chaining. + */ + public Builder setTitle( + java.lang.String value) { + if (value == null) { + throw new NullPointerException(); + } + + title_ = value; + onChanged(); + return this; + } + /** + * string title = 2; + * @return This builder for chaining. + */ + public Builder clearTitle() { + + title_ = getDefaultInstance().getTitle(); + onChanged(); + return this; + } + /** + * string title = 2; + * @param value The bytes for title to set. + * @return This builder for chaining. + */ + public Builder setTitleBytes( + com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + checkByteStringIsUtf8(value); + + title_ = value; + onChanged(); + return this; + } + + private java.lang.Object author_ = ""; + /** + * string author = 3; + * @return The author. + */ + public java.lang.String getAuthor() { + java.lang.Object ref = author_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + author_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + * string author = 3; + * @return The bytes for author. + */ + public com.google.protobuf.ByteString + getAuthorBytes() { + java.lang.Object ref = author_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + author_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + * string author = 3; + * @param value The author to set. + * @return This builder for chaining. + */ + public Builder setAuthor( + java.lang.String value) { + if (value == null) { + throw new NullPointerException(); + } + + author_ = value; + onChanged(); + return this; + } + /** + * string author = 3; + * @return This builder for chaining. + */ + public Builder clearAuthor() { + + author_ = getDefaultInstance().getAuthor(); + onChanged(); + return this; + } + /** + * string author = 3; + * @param value The bytes for author to set. + * @return This builder for chaining. + */ + public Builder setAuthorBytes( + com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + checkByteStringIsUtf8(value); + + author_ = value; + onChanged(); + return this; + } + + private int genre_ = 0; + /** + * .com.book.Genre genre = 4; + * @return The enum numeric value on the wire for genre. + */ + @java.lang.Override public int getGenreValue() { + return genre_; + } + /** + * .com.book.Genre genre = 4; + * @param value The enum numeric value on the wire for genre to set. + * @return This builder for chaining. + */ + public Builder setGenreValue(int value) { + + genre_ = value; + onChanged(); + return this; + } + /** + * .com.book.Genre genre = 4; + * @return The genre. + */ + @java.lang.Override + public com.example.spanner.protobuf.book.Genre getGenre() { + @SuppressWarnings("deprecation") + com.example.spanner.protobuf.book.Genre result = com.example.spanner.protobuf.book.Genre.valueOf(genre_); + return result == null ? com.example.spanner.protobuf.book.Genre.UNRECOGNIZED : result; + } + /** + * .com.book.Genre genre = 4; + * @param value The genre to set. + * @return This builder for chaining. + */ + public Builder setGenre(com.example.spanner.protobuf.book.Genre value) { + if (value == null) { + throw new NullPointerException(); + } + + genre_ = value.getNumber(); + onChanged(); + return this; + } + /** + * .com.book.Genre genre = 4; + * @return This builder for chaining. + */ + public Builder clearGenre() { + + genre_ = 0; + onChanged(); + return this; + } + @java.lang.Override + public final Builder setUnknownFields( + final com.google.protobuf.UnknownFieldSet unknownFields) { + return super.setUnknownFields(unknownFields); + } + + @java.lang.Override + public final Builder mergeUnknownFields( + final com.google.protobuf.UnknownFieldSet unknownFields) { + return super.mergeUnknownFields(unknownFields); + } + + + // @@protoc_insertion_point(builder_scope:com.book.Book) + } + + // @@protoc_insertion_point(class_scope:com.book.Book) + private static final com.example.spanner.protobuf.book.Book DEFAULT_INSTANCE; + static { + DEFAULT_INSTANCE = new com.example.spanner.protobuf.book.Book(); + } + + public static com.example.spanner.protobuf.book.Book getDefaultInstance() { + return DEFAULT_INSTANCE; + } + + private static final com.google.protobuf.Parser + PARSER = new com.google.protobuf.AbstractParser() { + @java.lang.Override + public Book parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return new Book(input, extensionRegistry); + } + }; + + public static com.google.protobuf.Parser parser() { + return PARSER; + } + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + @java.lang.Override + public com.example.spanner.protobuf.book.Book getDefaultInstanceForType() { + return DEFAULT_INSTANCE; + } + +} + diff --git a/samples/snippets/src/main/java/com/example/spanner/protobuf/book/BookOrBuilder.java b/samples/snippets/src/main/java/com/example/spanner/protobuf/book/BookOrBuilder.java new file mode 100644 index 00000000000..59f6d64d535 --- /dev/null +++ b/samples/snippets/src/main/java/com/example/spanner/protobuf/book/BookOrBuilder.java @@ -0,0 +1,50 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: book.proto + +package com.example.spanner.protobuf.book; + +public interface BookOrBuilder extends + // @@protoc_insertion_point(interface_extends:com.book.Book) + com.google.protobuf.MessageOrBuilder { + + /** + * int64 isbn = 1; + * @return The isbn. + */ + long getIsbn(); + + /** + * string title = 2; + * @return The title. + */ + java.lang.String getTitle(); + /** + * string title = 2; + * @return The bytes for title. + */ + com.google.protobuf.ByteString + getTitleBytes(); + + /** + * string author = 3; + * @return The author. + */ + java.lang.String getAuthor(); + /** + * string author = 3; + * @return The bytes for author. + */ + com.google.protobuf.ByteString + getAuthorBytes(); + + /** + * .com.book.Genre genre = 4; + * @return The enum numeric value on the wire for genre. + */ + int getGenreValue(); + /** + * .com.book.Genre genre = 4; + * @return The genre. + */ + com.example.spanner.protobuf.book.Genre getGenre(); +} diff --git a/samples/snippets/src/main/java/com/example/spanner/protobuf/book/BookProto.java b/samples/snippets/src/main/java/com/example/spanner/protobuf/book/BookProto.java new file mode 100644 index 00000000000..182a563804c --- /dev/null +++ b/samples/snippets/src/main/java/com/example/spanner/protobuf/book/BookProto.java @@ -0,0 +1,51 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: book.proto + +package com.example.spanner.protobuf.book; + +public final class BookProto { + private BookProto() {} + public static void registerAllExtensions( + com.google.protobuf.ExtensionRegistryLite registry) { + } + + public static void registerAllExtensions( + com.google.protobuf.ExtensionRegistry registry) { + registerAllExtensions( + (com.google.protobuf.ExtensionRegistryLite) registry); + } + static final com.google.protobuf.Descriptors.Descriptor + internal_static_com_book_Book_descriptor; + static final + com.google.protobuf.GeneratedMessageV3.FieldAccessorTable + internal_static_com_book_Book_fieldAccessorTable; + + public static com.google.protobuf.Descriptors.FileDescriptor + getDescriptor() { + return descriptor; + } + private static com.google.protobuf.Descriptors.FileDescriptor + descriptor; + static { + java.lang.String[] descriptorData = { + "\n\nbook.proto\022\010com.book\"S\n\004Book\022\014\n\004isbn\030\001" + + " \001(\003\022\r\n\005title\030\002 \001(\t\022\016\n\006author\030\003 \001(\t\022\036\n\005g" + + "enre\030\004 \001(\0162\017.com.book.Genre*8\n\005Genre\022\t\n\005" + + "BLUES\020\000\022\r\n\tCLASSICAL\020\001\022\013\n\007COUNTRY\020\002\022\010\n\004R" + + "OCK\020\003B@\n!com.example.spanner.protobuf.bo" + + "okB\tBookProtoP\001Z\016gaurav.purohitb\006proto3" + }; + descriptor = com.google.protobuf.Descriptors.FileDescriptor + .internalBuildGeneratedFileFrom(descriptorData, + new com.google.protobuf.Descriptors.FileDescriptor[] { + }); + internal_static_com_book_Book_descriptor = + getDescriptor().getMessageTypes().get(0); + internal_static_com_book_Book_fieldAccessorTable = new + com.google.protobuf.GeneratedMessageV3.FieldAccessorTable( + internal_static_com_book_Book_descriptor, + new java.lang.String[] { "Isbn", "Title", "Author", "Genre", }); + } + + // @@protoc_insertion_point(outer_class_scope) +} diff --git a/samples/snippets/src/main/java/com/example/spanner/protobuf/book/Genre.java b/samples/snippets/src/main/java/com/example/spanner/protobuf/book/Genre.java new file mode 100644 index 00000000000..c3887aa67ad --- /dev/null +++ b/samples/snippets/src/main/java/com/example/spanner/protobuf/book/Genre.java @@ -0,0 +1,131 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: book.proto + +package com.example.spanner.protobuf.book; + +/** + * Protobuf enum {@code com.book.Genre} + */ +public enum Genre + implements com.google.protobuf.ProtocolMessageEnum { + /** + * BLUES = 0; + */ + BLUES(0), + /** + * CLASSICAL = 1; + */ + CLASSICAL(1), + /** + * COUNTRY = 2; + */ + COUNTRY(2), + /** + * ROCK = 3; + */ + ROCK(3), + UNRECOGNIZED(-1), + ; + + /** + * BLUES = 0; + */ + public static final int BLUES_VALUE = 0; + /** + * CLASSICAL = 1; + */ + public static final int CLASSICAL_VALUE = 1; + /** + * COUNTRY = 2; + */ + public static final int COUNTRY_VALUE = 2; + /** + * ROCK = 3; + */ + public static final int ROCK_VALUE = 3; + + + public final int getNumber() { + if (this == UNRECOGNIZED) { + throw new java.lang.IllegalArgumentException( + "Can't get the number of an unknown enum value."); + } + return value; + } + + /** + * @param value The numeric wire value of the corresponding enum entry. + * @return The enum associated with the given numeric wire value. + * @deprecated Use {@link #forNumber(int)} instead. + */ + @java.lang.Deprecated + public static Genre valueOf(int value) { + return forNumber(value); + } + + /** + * @param value The numeric wire value of the corresponding enum entry. + * @return The enum associated with the given numeric wire value. + */ + public static Genre forNumber(int value) { + switch (value) { + case 0: return BLUES; + case 1: return CLASSICAL; + case 2: return COUNTRY; + case 3: return ROCK; + default: return null; + } + } + + public static com.google.protobuf.Internal.EnumLiteMap + internalGetValueMap() { + return internalValueMap; + } + private static final com.google.protobuf.Internal.EnumLiteMap< + Genre> internalValueMap = + new com.google.protobuf.Internal.EnumLiteMap() { + public Genre findValueByNumber(int number) { + return Genre.forNumber(number); + } + }; + + public final com.google.protobuf.Descriptors.EnumValueDescriptor + getValueDescriptor() { + if (this == UNRECOGNIZED) { + throw new java.lang.IllegalStateException( + "Can't get the descriptor of an unrecognized enum value."); + } + return getDescriptor().getValues().get(ordinal()); + } + public final com.google.protobuf.Descriptors.EnumDescriptor + getDescriptorForType() { + return getDescriptor(); + } + public static final com.google.protobuf.Descriptors.EnumDescriptor + getDescriptor() { + return com.example.spanner.protobuf.book.BookProto.getDescriptor().getEnumTypes().get(0); + } + + private static final Genre[] VALUES = values(); + + public static Genre valueOf( + com.google.protobuf.Descriptors.EnumValueDescriptor desc) { + if (desc.getType() != getDescriptor()) { + throw new java.lang.IllegalArgumentException( + "EnumValueDescriptor is not for this type."); + } + if (desc.getIndex() == -1) { + return UNRECOGNIZED; + } + return VALUES[desc.getIndex()]; + } + + private final int value; + + private Genre(int value) { + this.value = value; + } + + // @@protoc_insertion_point(enum_scope:com.book.Genre) +} + diff --git a/samples/snippets/src/main/java/com/example/spanner/protobuf/book/book.proto b/samples/snippets/src/main/java/com/example/spanner/protobuf/book/book.proto new file mode 100644 index 00000000000..d3dbf18cc7c --- /dev/null +++ b/samples/snippets/src/main/java/com/example/spanner/protobuf/book/book.proto @@ -0,0 +1,22 @@ +syntax = "proto3"; + +package com.book; + +option java_package = "com.example.spanner.protobuf.book"; +option java_outer_classname = "BookProto"; +option java_multiple_files = true; + +message Book { + int64 isbn = 1; + string title = 2; + string author = 3; + Genre genre = 4; +} + + +enum Genre { + BLUES = 0; + CLASSICAL = 1; + COUNTRY = 2; + ROCK = 3; +} \ No newline at end of file