From da2f8e8ef376956fbde9b12dcf363d5001f5c835 Mon Sep 17 00:00:00 2001 From: gauravpurohit Date: Tue, 6 Sep 2022 12:44:30 +0000 Subject: [PATCH 01/10] feat: Publishing Proto Changes --- .../main/java/com/google/spanner/v1/Type.java | 137 ++++++++++++++++++ .../java/com/google/spanner/v1/TypeCode.java | 12 ++ .../com/google/spanner/v1/TypeOrBuilder.java | 13 ++ .../java/com/google/spanner/v1/TypeProto.java | 37 ++--- .../main/proto/google/spanner/v1/type.proto | 5 + 5 files changed, 186 insertions(+), 18 deletions(-) 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 From 87ad55ae41d8f5c2a0c1d8930542fd2a750250da Mon Sep 17 00:00:00 2001 From: gauravpurohit Date: Tue, 13 Sep 2022 09:00:59 +0000 Subject: [PATCH 02/10] feat: Proto Message Implementation --- .../cloud/spanner/AbstractResultSet.java | 27 ++++++++ .../cloud/spanner/AbstractStructReader.java | 20 ++++++ .../cloud/spanner/ForwardingStructReader.java | 13 ++++ .../cloud/spanner/ProtoMessageWrapper.java | 26 +++++++ .../com/google/cloud/spanner/ResultSets.java | 13 ++++ .../java/com/google/cloud/spanner/Struct.java | 13 ++++ .../google/cloud/spanner/StructReader.java | 6 ++ .../java/com/google/cloud/spanner/Type.java | 22 ++++++ .../java/com/google/cloud/spanner/Value.java | 69 ++++++++++++++++++- .../com/google/cloud/spanner/ValueBinder.java | 5 ++ .../connection/DirectExecuteResultSet.java | 15 ++++ .../ReplaceableForwardingResultSet.java | 15 ++++ .../AbstractStructReaderTypesTest.java | 9 +++ 13 files changed, 252 insertions(+), 1 deletion(-) create mode 100644 google-cloud-spanner/src/main/java/com/google/cloud/spanner/ProtoMessageWrapper.java 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..0419375c3fa 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,7 +36,9 @@ 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.Value.KindCase; import com.google.spanner.v1.PartialResultSet; @@ -385,6 +387,8 @@ 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 PG_JSONB: builder.set(fieldName).to(Value.pgJsonb((String) value)); break; @@ -504,6 +508,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 +660,17 @@ public boolean isNull(int columnIndex) { return rowData.get(columnIndex) == null; } + @Override + public byte[] getProtoMessageInternal(int columnIndex) { + return (byte[]) rowData.get(columnIndex); + } + + @Override + public void getProtoMessageInternal(int columnIndex, AbstractMessage m) + throws InvalidProtocolBufferException { + m.toBuilder().mergeFrom(getProtoMessage(columnIndex)); + } + @Override protected boolean getBooleanInternal(int columnIndex) { return (Boolean) rowData.get(columnIndex); @@ -1368,6 +1384,17 @@ protected String getStringInternal(int columnIndex) { return currRow().getStringInternal(columnIndex); } + @Override + protected byte[] getProtoMessageInternal(int columnIndex) { + return currRow().getProtoMessageInternal(columnIndex); + } + + @Override + protected void getProtoMessageInternal(int columnIndex, AbstractMessage m) + throws InvalidProtocolBufferException { + currRow().getProtoMessageInternal(columnIndex, m); + } + @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..564a41a1a33 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,6 +21,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.InvalidProtocolBufferException; import java.math.BigDecimal; import java.util.Arrays; import java.util.List; @@ -58,6 +60,11 @@ protected String getPgJsonbInternal(int columnIndex) { protected abstract Date getDateInternal(int columnIndex); + protected abstract byte[] getProtoMessageInternal(int columnIndex); + + protected abstract void getProtoMessageInternal(int columnIndex, AbstractMessage m) + throws InvalidProtocolBufferException; + protected Value getValueInternal(int columnIndex) { throw new UnsupportedOperationException("method should be overwritten"); } @@ -249,6 +256,19 @@ public Date getDate(String columnName) { return getDateInternal(columnIndex); } + @Override + public byte[] getProtoMessage(int columnIndex) { + checkNonNullOfType(columnIndex, Type.proto(), columnIndex); + return getProtoMessageInternal(columnIndex); + } + + @Override + public void getProtoMessage(int columnIndex, AbstractMessage m) + throws InvalidProtocolBufferException { + checkNonNullOfType(columnIndex, Type.proto(), columnIndex); + 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..73011dc027b 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,6 +22,8 @@ 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 java.math.BigDecimal; import java.util.List; @@ -382,6 +384,17 @@ public List getStructList(String columnName) { return delegate.get().getStructList(columnName); } + @Override + public byte[] getProtoMessage(int columnIndex) { + return delegate.get().getProtoMessage(columnIndex); + } + + @Override + public void getProtoMessage(int columnIndex, AbstractMessage m) + throws InvalidProtocolBufferException { + delegate.get().getProtoMessage(columnIndex, m); + } + @Override public Value getValue(int columnIndex) { checkValidState(); 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..2bad327f7d3 --- /dev/null +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/ProtoMessageWrapper.java @@ -0,0 +1,26 @@ +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..bb02bf64abd 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,6 +29,8 @@ 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.spanner.v1.ResultSetStats; import java.math.BigDecimal; import java.util.List; @@ -293,6 +295,17 @@ public Date getDate(String columnName) { return getCurrentRowAsStruct().getDate(columnName); } + @Override + public byte[] getProtoMessage(int columnIndex) { + return getCurrentRowAsStruct().getProtoMessage(columnIndex); + } + + @Override + public void getProtoMessage(int columnIndex, AbstractMessage m) + throws InvalidProtocolBufferException { + getCurrentRowAsStruct().getProtoMessage(columnIndex, m); + } + @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..ad1017c13fe 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,6 +28,8 @@ 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 java.io.Serializable; import java.math.BigDecimal; import java.util.ArrayList; @@ -217,6 +219,17 @@ protected Date getDateInternal(int columnIndex) { return values.get(columnIndex).getDate(); } + @Override + protected byte[] getProtoMessageInternal(int columnIndex) { + return values.get(columnIndex).getProtoMessage(); + } + + @Override + protected void getProtoMessageInternal(int columnIndex, AbstractMessage m) + throws InvalidProtocolBufferException { + values.get(columnIndex).getProtoMessage(m); + } + @Override protected Value getValueInternal(int columnIndex) { return values.get(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..3c0c6c479d8 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,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.InvalidProtocolBufferException; import java.math.BigDecimal; import java.util.List; @@ -303,4 +305,8 @@ default List getPgJsonbList(String columnName) { * Returns the value of a non-{@code NULL} column with type {@code Type.array(Type.struct(...))}. */ List getStructList(String columnName); + + byte[] getProtoMessage(int columnIndex); + + void getProtoMessage(int columnIndex, AbstractMessage m) throws InvalidProtocolBufferException; } 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..f254aa00ab9 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; @@ -217,8 +221,16 @@ 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); + } + /** - * Returns a {@code BYTES} value. + * Returns a {@code BYTES} value. Returns a {@code BYTES} value. * * @param v the value, which may be null */ @@ -541,6 +553,18 @@ public String getPgJsonb() { throw new UnsupportedOperationException("Not implemented"); } + byte[] getProtoMessage() { + throw new UnsupportedOperationException("Not implemented"); + } + + public void getProtoMessage(AbstractMessage message) throws InvalidProtocolBufferException { + throw new UnsupportedOperationException("Not implemented"); + } + + public ProtocolMessageEnum getProtoEnum() { + throw new UnsupportedOperationException("Not implemented"); + } + /** * Returns the value of a {@code BYTES}-typed instance. * @@ -851,6 +875,16 @@ public String getPgJsonb() { throw defaultGetter(Type.pgJsonb()); } + @Override + byte[] getProtoMessage() { + throw defaultGetter(Type.proto()); + } + + @Override + public void getProtoMessage(AbstractMessage message) throws InvalidProtocolBufferException { + throw defaultGetter(Type.proto()); + } + @Override public ByteArray getBytes() { throw defaultGetter(Type.bytes()); @@ -1329,6 +1363,37 @@ 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 + byte[] getProtoMessage() { + return value.serializedMessage; + } + + @Override + public void getProtoMessage(AbstractMessage message) throws InvalidProtocolBufferException { + message.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 TimestampImpl extends AbstractObjectValue { private static final String COMMIT_TIMESTAMP_STRING = "spanner.commit_timestamp()"; @@ -1971,6 +2036,8 @@ 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.getProtoMessage(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..b4efbac5f4e 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,7 @@ import com.google.cloud.ByteArray; import com.google.cloud.Date; import com.google.cloud.Timestamp; +import com.google.protobuf.GeneratedMessage; import java.math.BigDecimal; import javax.annotation.Nullable; @@ -95,6 +96,10 @@ public R to(@Nullable String value) { return handle(Value.string(value)); } + public R to(@Nullable GeneratedMessage m) { + return handle(Value.protoMessage(m)); + } + /** 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/DirectExecuteResultSet.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/DirectExecuteResultSet.java index 8fb0bbe4409..e95d9027dca 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,6 +25,8 @@ 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.spanner.v1.ResultSetStats; import java.math.BigDecimal; import java.util.List; @@ -431,6 +433,19 @@ public List getStructList(String columnName) { return delegate.getStructList(columnName); } + @Override + public byte[] getProtoMessage(int columnIndex) { + Preconditions.checkState(nextCalledByClient, MISSING_NEXT_CALL); + return delegate.getProtoMessage(columnIndex); + } + + @Override + public void getProtoMessage(int columnIndex, AbstractMessage m) + throws InvalidProtocolBufferException { + Preconditions.checkState(nextCalledByClient, MISSING_NEXT_CALL); + delegate.getProtoMessage(columnIndex, 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..1aed592c042 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,6 +27,8 @@ 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.spanner.v1.ResultSetStats; import java.math.BigDecimal; import java.util.List; @@ -435,4 +437,17 @@ public List getStructList(String columnName) { checkClosed(); return delegate.getStructList(columnName); } + + @Override + public byte[] getProtoMessage(int columnIndex) { + checkClosed(); + return delegate.getProtoMessage(columnIndex); + } + + @Override + public void getProtoMessage(int columnIndex, AbstractMessage m) + throws InvalidProtocolBufferException { + checkClosed(); + delegate.getProtoMessage(columnIndex, m); + } } 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..dcb63ed5467 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,7 @@ import com.google.cloud.Date; import com.google.cloud.Timestamp; import com.google.common.base.Throwables; +import com.google.protobuf.AbstractMessage; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.math.BigDecimal; @@ -95,6 +96,14 @@ protected Date getDateInternal(int columnIndex) { return null; } + @Override + protected byte[] getProtoMessageInternal(int columnIndex) { + return null; + } + + @Override + protected void getProtoMessageInternal(int columnIndex, AbstractMessage m) {} + @Override protected Value getValueInternal(int columnIndex) { return null; From d936a4e525fa863f72b23c1cc271b1e88caf31d7 Mon Sep 17 00:00:00 2001 From: gauravpurohit Date: Tue, 13 Sep 2022 09:18:27 +0000 Subject: [PATCH 03/10] feat: Sample Proto and generated Files --- .../example/spanner/protobuf/book/Book.java | 856 ++++++++++++++++++ .../spanner/protobuf/book/BookOrBuilder.java | 50 + .../spanner/protobuf/book/BookProto.java | 51 ++ .../example/spanner/protobuf/book/Genre.java | 131 +++ .../example/spanner/protobuf/book/book.proto | 22 + 5 files changed, 1110 insertions(+) create mode 100644 samples/snippets/src/main/java/com/example/spanner/protobuf/book/Book.java create mode 100644 samples/snippets/src/main/java/com/example/spanner/protobuf/book/BookOrBuilder.java create mode 100644 samples/snippets/src/main/java/com/example/spanner/protobuf/book/BookProto.java create mode 100644 samples/snippets/src/main/java/com/example/spanner/protobuf/book/Genre.java create mode 100644 samples/snippets/src/main/java/com/example/spanner/protobuf/book/book.proto 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 From cab6ab44677312aa8b369e8a798933e62d97f2fc Mon Sep 17 00:00:00 2001 From: gauravpurohit Date: Thu, 15 Sep 2022 09:21:12 +0000 Subject: [PATCH 04/10] feat: Implementation using Builder without reflection --- .../cloud/spanner/AbstractResultSet.java | 8 +++---- .../cloud/spanner/AbstractStructReader.java | 21 ++++++++++++++++--- .../cloud/spanner/ForwardingStructReader.java | 4 ++-- .../com/google/cloud/spanner/ResultSets.java | 15 +++++++++++-- .../java/com/google/cloud/spanner/Struct.java | 4 ++-- .../google/cloud/spanner/StructReader.java | 14 +++++++++---- .../java/com/google/cloud/spanner/Value.java | 11 ++++++---- .../connection/DirectExecuteResultSet.java | 4 ++-- .../ReplaceableForwardingResultSet.java | 4 ++-- .../AbstractStructReaderTypesTest.java | 4 +++- 10 files changed, 63 insertions(+), 26 deletions(-) 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 0419375c3fa..589fddb5cb0 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 @@ -666,9 +666,9 @@ public byte[] getProtoMessageInternal(int columnIndex) { } @Override - public void getProtoMessageInternal(int columnIndex, AbstractMessage m) + public T getProtoMessageInternal(int columnIndex, T m) throws InvalidProtocolBufferException { - m.toBuilder().mergeFrom(getProtoMessage(columnIndex)); + return (T) m.toBuilder().mergeFrom(getProtoMessage(columnIndex)).build(); } @Override @@ -1390,9 +1390,9 @@ protected byte[] getProtoMessageInternal(int columnIndex) { } @Override - protected void getProtoMessageInternal(int columnIndex, AbstractMessage m) + protected T getProtoMessageInternal(int columnIndex, T m) throws InvalidProtocolBufferException { - currRow().getProtoMessageInternal(columnIndex, m); + return currRow().getProtoMessageInternal(columnIndex, m); } @Override 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 564a41a1a33..8d3db2feb91 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 @@ -62,7 +62,7 @@ protected String getPgJsonbInternal(int columnIndex) { protected abstract byte[] getProtoMessageInternal(int columnIndex); - protected abstract void getProtoMessageInternal(int columnIndex, AbstractMessage m) + protected abstract T getProtoMessageInternal(int columnIndex, T m) throws InvalidProtocolBufferException; protected Value getValueInternal(int columnIndex) { @@ -263,10 +263,25 @@ public byte[] getProtoMessage(int columnIndex) { } @Override - public void getProtoMessage(int columnIndex, AbstractMessage m) + public byte[] getProtoMessage(String columnName) { + int columnIndex = getColumnIndex(columnName); + checkNonNullOfType(columnIndex, Type.proto(), columnName); + return getProtoMessageInternal(columnIndex); + } + + @Override + public T getProtoMessage(int columnIndex, T m) throws InvalidProtocolBufferException { checkNonNullOfType(columnIndex, Type.proto(), columnIndex); - getProtoMessageInternal(columnIndex, m); + 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 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 73011dc027b..1c66f9a009f 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 @@ -390,9 +390,9 @@ public byte[] getProtoMessage(int columnIndex) { } @Override - public void getProtoMessage(int columnIndex, AbstractMessage m) + public T getProtoMessage(int columnIndex, T m) throws InvalidProtocolBufferException { - delegate.get().getProtoMessage(columnIndex, m); + return delegate.get().getProtoMessage(columnIndex, m); } @Override 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 bb02bf64abd..4ed392680a1 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 @@ -301,9 +301,20 @@ public byte[] getProtoMessage(int columnIndex) { } @Override - public void getProtoMessage(int columnIndex, AbstractMessage m) + public byte[] getProtoMessage(String columnName) { + return getCurrentRowAsStruct().getProtoMessage(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 { - getCurrentRowAsStruct().getProtoMessage(columnIndex, m); + return getCurrentRowAsStruct().getProtoMessage(columnName, m); } @Override 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 ad1017c13fe..f23cdc8de8d 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 @@ -225,9 +225,9 @@ protected byte[] getProtoMessageInternal(int columnIndex) { } @Override - protected void getProtoMessageInternal(int columnIndex, AbstractMessage m) + protected T getProtoMessageInternal(int columnIndex, T m) throws InvalidProtocolBufferException { - values.get(columnIndex).getProtoMessage(m); + return values.get(columnIndex).getProtoMessage(m); } @Override 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 3c0c6c479d8..f4141226c43 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 @@ -296,6 +296,16 @@ 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); + byte[] getProtoMessage(int columnIndex); + + byte[] getProtoMessage(String columnName); + + T getProtoMessage(int columnIndex, T m) + throws InvalidProtocolBufferException; + + T getProtoMessage(String columnName, T m) + throws InvalidProtocolBufferException; + /** * Returns the value of a non-{@code NULL} column with type {@code Type.array(Type.struct(...))}. */ @@ -305,8 +315,4 @@ default List getPgJsonbList(String columnName) { * Returns the value of a non-{@code NULL} column with type {@code Type.array(Type.struct(...))}. */ List getStructList(String columnName); - - byte[] getProtoMessage(int columnIndex); - - void getProtoMessage(int columnIndex, AbstractMessage m) throws InvalidProtocolBufferException; } 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 f254aa00ab9..ee34e5c0eb1 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 @@ -557,7 +557,8 @@ byte[] getProtoMessage() { throw new UnsupportedOperationException("Not implemented"); } - public void getProtoMessage(AbstractMessage message) throws InvalidProtocolBufferException { + public T getProtoMessage(T m) + throws InvalidProtocolBufferException { throw new UnsupportedOperationException("Not implemented"); } @@ -881,7 +882,8 @@ byte[] getProtoMessage() { } @Override - public void getProtoMessage(AbstractMessage message) throws InvalidProtocolBufferException { + public T getProtoMessage(T m) + throws InvalidProtocolBufferException { throw defaultGetter(Type.proto()); } @@ -1378,8 +1380,9 @@ byte[] getProtoMessage() { } @Override - public void getProtoMessage(AbstractMessage message) throws InvalidProtocolBufferException { - message.toBuilder().mergeFrom(value.serializedMessage); + public T getProtoMessage(T m) + throws InvalidProtocolBufferException { + return (T) m.toBuilder().mergeFrom(value.serializedMessage); } @Override 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 e95d9027dca..07bb33176ac 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 @@ -440,10 +440,10 @@ public byte[] getProtoMessage(int columnIndex) { } @Override - public void getProtoMessage(int columnIndex, AbstractMessage m) + public T getProtoMessage(int columnIndex, T m) throws InvalidProtocolBufferException { Preconditions.checkState(nextCalledByClient, MISSING_NEXT_CALL); - delegate.getProtoMessage(columnIndex, m); + return delegate.getProtoMessage(columnIndex, m); } @Override 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 1aed592c042..7700e16b2c8 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 @@ -445,9 +445,9 @@ public byte[] getProtoMessage(int columnIndex) { } @Override - public void getProtoMessage(int columnIndex, AbstractMessage m) + public T getProtoMessage(int columnIndex, T m) throws InvalidProtocolBufferException { checkClosed(); - delegate.getProtoMessage(columnIndex, m); + return delegate.getProtoMessage(columnIndex, m); } } 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 dcb63ed5467..a1e8b6474c7 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 @@ -102,7 +102,9 @@ protected byte[] getProtoMessageInternal(int columnIndex) { } @Override - protected void getProtoMessageInternal(int columnIndex, AbstractMessage m) {} + protected T getProtoMessageInternal(int columnIndex, T m) { + return null; + } @Override protected Value getValueInternal(int columnIndex) { From 0753f064a94780787e56947f41311c88c6c4eade Mon Sep 17 00:00:00 2001 From: gauravpurohit Date: Thu, 15 Sep 2022 10:34:04 +0000 Subject: [PATCH 05/10] feat: Adding samples for querying and write proto using mutations --- .../protobuf/QueryProtoColumnSample.java | 43 +++++++++++++++++ .../protobuf/UpdateProtoColumnSample.java | 46 +++++++++++++++++++ 2 files changed, 89 insertions(+) create mode 100644 samples/snippets/src/main/java/com/example/spanner/protobuf/QueryProtoColumnSample.java create mode 100644 samples/snippets/src/main/java/com/example/spanner/protobuf/UpdateProtoColumnSample.java 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..b6125aec2b8 --- /dev/null +++ b/samples/snippets/src/main/java/com/example/spanner/protobuf/QueryProtoColumnSample.java @@ -0,0 +1,43 @@ +package com.example.spanner.protobuf; + +import com.example.spanner.protobuf.book.Book; +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; + +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\n" + "FROM Library").build(); + + try (ResultSet resultSet = client.singleUse().executeQuery(statement)) { + while (resultSet.next()) { + System.out.printf( + "bookId: %s, bookProto: %s%n", + resultSet.getLong("bookId"), + resultSet.getProtoMessage("bookProto", Book.getDefaultInstance())); + } + } 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..a5476d70739 --- /dev/null +++ b/samples/snippets/src/main/java/com/example/spanner/protobuf/UpdateProtoColumnSample.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.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)) + .build())); + } +} From b328e9008bfaf5d4e32b4b6ad3b6b0de075fb6e9 Mon Sep 17 00:00:00 2001 From: gauravpurohit Date: Thu, 15 Sep 2022 10:50:10 +0000 Subject: [PATCH 06/10] feat: Implementing proto utilities in the derived classes --- .../cloud/spanner/ForwardingStructReader.java | 11 +++++++++++ .../cloud/spanner/ProtoMessageWrapper.java | 16 ++++++++++++++++ .../spanner/connection/ChecksumResultSet.java | 3 +++ .../connection/DirectExecuteResultSet.java | 13 +++++++++++++ .../ReplaceableForwardingResultSet.java | 13 +++++++++++++ 5 files changed, 56 insertions(+) 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 1c66f9a009f..cfb674f5a1c 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 @@ -389,12 +389,23 @@ public byte[] getProtoMessage(int columnIndex) { return delegate.get().getProtoMessage(columnIndex); } + @Override + public byte[] getProtoMessage(String columnName) { + return delegate.get().getProtoMessage(columnName); + } + @Override public T getProtoMessage(int columnIndex, T m) throws InvalidProtocolBufferException { return delegate.get().getProtoMessage(columnIndex, m); } + @Override + public T getProtoMessage(String columnName, T m) + throws InvalidProtocolBufferException { + return delegate.get().getProtoMessage(columnName, m); + } + @Override public Value getValue(int columnIndex) { checkValidState(); 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 index 2bad327f7d3..cb731d2a9a5 100644 --- 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 @@ -1,3 +1,19 @@ +/* + * 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; 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..18fa48f2798 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 @@ -248,6 +248,9 @@ public void funnel(Struct row, PrimitiveSink into) { case JSON: funnelValue(type, row.getJson(i), into); break; + case PROTO: + funnelValue(type, row.getProtoMessage(i), into); + break; case PG_JSONB: funnelValue(type, row.getPgJsonb(i), into); break; 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 07bb33176ac..138bfea3ea6 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 @@ -439,6 +439,12 @@ public byte[] getProtoMessage(int columnIndex) { return delegate.getProtoMessage(columnIndex); } + @Override + public byte[] getProtoMessage(String columnName) { + Preconditions.checkState(nextCalledByClient, MISSING_NEXT_CALL); + return delegate.getProtoMessage(columnName); + } + @Override public T getProtoMessage(int columnIndex, T m) throws InvalidProtocolBufferException { @@ -446,6 +452,13 @@ public T getProtoMessage(int columnIndex, T m) 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 7700e16b2c8..49b1820fce5 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 @@ -444,10 +444,23 @@ public byte[] getProtoMessage(int columnIndex) { return delegate.getProtoMessage(columnIndex); } + @Override + public byte[] getProtoMessage(String columnName) { + checkClosed(); + return delegate.getProtoMessage(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); + } } From 8792e25f635846bc93763dcb0935e697a9474976 Mon Sep 17 00:00:00 2001 From: gauravpurohit Date: Mon, 19 Sep 2022 08:54:57 +0000 Subject: [PATCH 07/10] feat: Adding support for PROTO_ENUM --- .../cloud/spanner/AbstractResultSet.java | 22 ++++++- .../cloud/spanner/AbstractStructReader.java | 21 ++++++ .../cloud/spanner/ForwardingStructReader.java | 20 ++++++ .../cloud/spanner/ProtoEnumWrapper.java | 33 ++++++++++ .../com/google/cloud/spanner/ResultSets.java | 14 ++++ .../java/com/google/cloud/spanner/Struct.java | 14 ++++ .../google/cloud/spanner/StructReader.java | 9 +++ .../java/com/google/cloud/spanner/Value.java | 64 ++++++++++++++++++- .../com/google/cloud/spanner/ValueBinder.java | 5 ++ .../spanner/connection/ChecksumResultSet.java | 1 + .../connection/DirectExecuteResultSet.java | 16 +++++ .../ReplaceableForwardingResultSet.java | 16 +++++ .../protobuf/QueryProtoColumnSample.java | 15 ++++- .../protobuf/UpdateProtoColumnSample.java | 2 + 14 files changed, 246 insertions(+), 6 deletions(-) create mode 100644 google-cloud-spanner/src/main/java/com/google/cloud/spanner/ProtoEnumWrapper.java 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 589fddb5cb0..436ab62a0fb 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 @@ -40,6 +40,7 @@ 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; @@ -54,6 +55,8 @@ import io.opencensus.trace.Tracing; import java.io.IOException; import java.io.Serializable; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; import java.math.BigDecimal; import java.util.AbstractList; import java.util.ArrayList; @@ -389,6 +392,8 @@ private Object writeReplace() { 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; @@ -494,6 +499,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: @@ -668,7 +674,15 @@ public byte[] getProtoMessageInternal(int columnIndex) { @Override public T getProtoMessageInternal(int columnIndex, T m) throws InvalidProtocolBufferException { - return (T) m.toBuilder().mergeFrom(getProtoMessage(columnIndex)).build(); + return (T) m.toBuilder().mergeFrom(getProtoMessageInternal(columnIndex)).build(); + } + + @Override + protected T getProtoEnumInternal(int columnIndex, + Class clazz) + throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { + Method parseMethod = clazz.getMethod("forNumber", int.class); + return clazz.cast(parseMethod.invoke(null, (int) getLongInternal(columnIndex))); } @Override @@ -1395,6 +1409,12 @@ protected T getProtoMessageInternal(int columnIndex, return currRow().getProtoMessageInternal(columnIndex, m); } + @Override + protected T getProtoEnumInternal(int columnIndex, Class clazz) + throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { + return currRow().getProtoEnumInternal(columnIndex, clazz); + } + @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 8d3db2feb91..23d0bb29d12 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 @@ -23,6 +23,8 @@ import com.google.cloud.Timestamp; import com.google.protobuf.AbstractMessage; import com.google.protobuf.InvalidProtocolBufferException; +import com.google.protobuf.ProtocolMessageEnum; +import java.lang.reflect.InvocationTargetException; import java.math.BigDecimal; import java.util.Arrays; import java.util.List; @@ -65,6 +67,10 @@ protected String getPgJsonbInternal(int columnIndex) { protected abstract T getProtoMessageInternal(int columnIndex, T m) throws InvalidProtocolBufferException; + protected abstract T getProtoEnumInternal(int columnIndex, + Class clazz) + throws NoSuchMethodException, InvocationTargetException, IllegalAccessException; + protected Value getValueInternal(int columnIndex) { throw new UnsupportedOperationException("method should be overwritten"); } @@ -269,6 +275,21 @@ public byte[] getProtoMessage(String columnName) { return getProtoMessageInternal(columnIndex); } + @Override + public T getProtoEnum(int columnIndex, Class clazz) + throws NoSuchMethodException, InvocationTargetException, IllegalAccessException{ + checkNonNullOfType(columnIndex, Type.protoEnum(), columnIndex); + return getProtoEnumInternal(columnIndex, clazz); + } + + @Override + public T getProtoEnum(String columnName, Class clazz) + throws NoSuchMethodException, InvocationTargetException, IllegalAccessException{ + int columnIndex = getColumnIndex(columnName); + checkNonNullOfType(columnIndex, Type.proto(), columnName); + return getProtoEnumInternal(columnIndex, clazz); + } + @Override public T getProtoMessage(int columnIndex, T m) throws InvalidProtocolBufferException { 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 cfb674f5a1c..6e0261a4f90 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 @@ -24,6 +24,8 @@ import com.google.common.base.Suppliers; import com.google.protobuf.AbstractMessage; import com.google.protobuf.InvalidProtocolBufferException; +import com.google.protobuf.ProtocolMessageEnum; +import java.lang.reflect.InvocationTargetException; import java.math.BigDecimal; import java.util.List; @@ -386,26 +388,44 @@ public List getStructList(String columnName) { @Override public byte[] getProtoMessage(int columnIndex) { + checkValidState(); return delegate.get().getProtoMessage(columnIndex); } @Override public byte[] getProtoMessage(String columnName) { + checkValidState(); return delegate.get().getProtoMessage(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, Class clazz) + throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { + checkValidState(); + return delegate.get().getProtoEnum(columnIndex, clazz); + } + + @Override + public T getProtoEnum(String columnName, Class clazz) + throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { + checkValidState(); + return delegate.get().getProtoEnum(columnName, clazz); + } + @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/ResultSets.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/ResultSets.java index 4ed392680a1..ccc229df10d 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 @@ -31,7 +31,9 @@ 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.lang.reflect.InvocationTargetException; import java.math.BigDecimal; import java.util.List; @@ -317,6 +319,18 @@ public T getProtoMessage(String columnName, T m) return getCurrentRowAsStruct().getProtoMessage(columnName, m); } + @Override + public T getProtoEnum(int columnIndex, Class clazz) + throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { + return getCurrentRowAsStruct().getProtoEnum(columnIndex, clazz); + } + + @Override + public T getProtoEnum(String columnName, Class clazz) + throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { + return getCurrentRowAsStruct().getProtoEnum(columnName, clazz); + } + @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 f23cdc8de8d..8e5b7ff3bda 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 @@ -30,7 +30,10 @@ 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.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; import java.math.BigDecimal; import java.util.ArrayList; import java.util.List; @@ -230,6 +233,14 @@ protected T getProtoMessageInternal(int columnIndex, return values.get(columnIndex).getProtoMessage(m); } + @Override + protected T getProtoEnumInternal(int columnIndex, + Class clazz) + throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { + Method parseMethod = clazz.getMethod("forNumber", int.class); + return clazz.cast(parseMethod.invoke(null, (int) values.get(columnIndex).getInt64())); + } + @Override protected Value getValueInternal(int columnIndex) { return values.get(columnIndex); @@ -367,6 +378,7 @@ private Object getAsObject(int columnIndex) { case BOOL: return getBooleanInternal(columnIndex); case INT64: + case PROTO_ENUM: return getLongInternal(columnIndex); case FLOAT64: return getDoubleInternal(columnIndex); @@ -378,6 +390,8 @@ private Object getAsObject(int columnIndex) { return getStringInternal(columnIndex); case JSON: return getJsonInternal(columnIndex); + case PROTO: + return getProtoMessageInternal(columnIndex); case PG_JSONB: return getPgJsonbInternal(columnIndex); case BYTES: 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 f4141226c43..82241ff10dc 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 @@ -21,6 +21,8 @@ import com.google.cloud.Timestamp; import com.google.protobuf.AbstractMessage; import com.google.protobuf.InvalidProtocolBufferException; +import com.google.protobuf.ProtocolMessageEnum; +import java.lang.reflect.InvocationTargetException; import java.math.BigDecimal; import java.util.List; @@ -306,6 +308,13 @@ T getProtoMessage(int columnIndex, T m) T getProtoMessage(String columnName, T m) throws InvalidProtocolBufferException; + T getProtoEnum(int columnIndex, Class clazz) + throws NoSuchMethodException, InvocationTargetException, IllegalAccessException; + + T getProtoEnum(String columnName, Class clazz) + throws NoSuchMethodException, InvocationTargetException, IllegalAccessException; + + /** * 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/Value.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/Value.java index ee34e5c0eb1..2100038efc7 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 @@ -31,6 +31,8 @@ import com.google.protobuf.NullValue; import com.google.protobuf.ProtocolMessageEnum; import java.io.Serializable; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; import java.math.BigDecimal; import java.util.ArrayList; import java.util.Arrays; @@ -229,7 +231,15 @@ 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); + } + + /**e * Returns a {@code BYTES} value. Returns a {@code BYTES} value. * * @param v the value, which may be null @@ -562,7 +572,8 @@ public T getProtoMessage(T m) throw new UnsupportedOperationException("Not implemented"); } - public ProtocolMessageEnum getProtoEnum() { + public T getProtoEnum(Class clazz) + throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { throw new UnsupportedOperationException("Not implemented"); } @@ -887,6 +898,12 @@ public T getProtoMessage(T m) throw defaultGetter(Type.proto()); } + @Override + public T getProtoEnum(Class clazz) + throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { + throw defaultGetter(Type.protoEnum()); + } + @Override public ByteArray getBytes() { throw defaultGetter(Type.bytes()); @@ -1376,12 +1393,16 @@ private ProtoMessageImpl(boolean isNull, byte[] serializedProtoArray) { @Override byte[] getProtoMessage() { + checkType(Type.proto()); + checkNotNull(); return value.serializedMessage; } @Override public T getProtoMessage(T m) throws InvalidProtocolBufferException { + checkType(Type.proto()); + checkNotNull(); return (T) m.toBuilder().mergeFrom(value.serializedMessage); } @@ -1397,6 +1418,43 @@ void valueToString(StringBuilder b) { } } + 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(Class clazz) + throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { + checkType(Type.protoEnum()); + checkNotNull(); + Method parseMethod = clazz.getMethod("forNumber", int.class); + return clazz.cast(parseMethod.invoke(null, 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()"; @@ -2041,6 +2099,8 @@ private Value getValue(int fieldIndex) { return Value.timestamp(value.getTimestamp(fieldIndex)); case PROTO: return Value.protoMessage(value.getProtoMessage(fieldIndex)); + 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 b4efbac5f4e..b8d266b7756 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 @@ -20,6 +20,7 @@ import com.google.cloud.Date; import com.google.cloud.Timestamp; import com.google.protobuf.GeneratedMessage; +import com.google.protobuf.ProtocolMessageEnum; import java.math.BigDecimal; import javax.annotation.Nullable; @@ -100,6 +101,10 @@ public R to(@Nullable GeneratedMessage 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 18fa48f2798..4f0808b9631 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 @@ -240,6 +240,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 138bfea3ea6..4137b2c9def 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 @@ -27,7 +27,9 @@ 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.lang.reflect.InvocationTargetException; import java.math.BigDecimal; import java.util.List; @@ -445,6 +447,20 @@ public byte[] getProtoMessage(String columnName) { return delegate.getProtoMessage(columnName); } + @Override + public T getProtoEnum(int columnIndex, Class clazz) + throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { + Preconditions.checkState(nextCalledByClient, MISSING_NEXT_CALL); + return delegate.getProtoEnum(columnIndex, clazz); + } + + @Override + public T getProtoEnum(String columnName, Class clazz) + throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { + Preconditions.checkState(nextCalledByClient, MISSING_NEXT_CALL); + return delegate.getProtoEnum(columnName, clazz); + } + @Override public T getProtoMessage(int columnIndex, T m) throws InvalidProtocolBufferException { 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 49b1820fce5..7244ee89c76 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 @@ -29,7 +29,9 @@ 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.lang.reflect.InvocationTargetException; import java.math.BigDecimal; import java.util.List; @@ -463,4 +465,18 @@ public T getProtoMessage(String columnName, T m) checkClosed(); return delegate.getProtoMessage(columnName, m); } + + @Override + public T getProtoEnum(int columnIndex, Class clazz) + throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { + checkClosed(); + return delegate.getProtoEnum(columnIndex, clazz); + } + + @Override + public T getProtoEnum(String columnName, Class clazz) + throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { + checkClosed(); + return delegate.getProtoEnum(columnName, clazz); + } } 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 index b6125aec2b8..fa2c644fa6d 100644 --- a/samples/snippets/src/main/java/com/example/spanner/protobuf/QueryProtoColumnSample.java +++ b/samples/snippets/src/main/java/com/example/spanner/protobuf/QueryProtoColumnSample.java @@ -1,6 +1,7 @@ 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; @@ -8,6 +9,7 @@ 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() { @@ -27,17 +29,24 @@ static void queryProtoColumn() { static void queryProtoColumn(DatabaseClient client) throws InvalidProtocolBufferException { Statement statement = - Statement.newBuilder("SELECT bookId, bookProto\n" + "FROM Library").build(); + 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%n", + "bookId: %s, bookProto: %s, genre: %s %n", resultSet.getLong("bookId"), - resultSet.getProtoMessage("bookProto", Book.getDefaultInstance())); + resultSet.getProtoMessage("bookProto", Book.getDefaultInstance()), + resultSet.getProtoEnum("genre", Genre.class)); } } catch (InvalidProtocolBufferException e) { e.printStackTrace(); + } catch (InvocationTargetException e) { + e.printStackTrace(); + } catch (NoSuchMethodException e) { + e.printStackTrace(); + } catch (IllegalAccessException 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 index a5476d70739..7ede67b1ce7 100644 --- a/samples/snippets/src/main/java/com/example/spanner/protobuf/UpdateProtoColumnSample.java +++ b/samples/snippets/src/main/java/com/example/spanner/protobuf/UpdateProtoColumnSample.java @@ -41,6 +41,8 @@ static void updateProtoData(DatabaseClient client) { .to(4L) .set("bookProto") .to(Value.protoMessage(bookProto)) + .set("genre") + .to(Value.protoEnum(Genre.ROCK)) .build())); } } From 84648bd18a3913425a1a64de5666e48cd1ed8505 Mon Sep 17 00:00:00 2001 From: gauravpurohit Date: Fri, 23 Sep 2022 11:49:44 +0000 Subject: [PATCH 08/10] feat: Deserializing ENUMS using lambda methods --- .../cloud/spanner/AbstractResultSet.java | 17 +++++++---------- .../cloud/spanner/AbstractStructReader.java | 19 +++++++++---------- .../cloud/spanner/ForwardingStructReader.java | 14 +++++++------- .../com/google/cloud/spanner/ResultSets.java | 14 +++++++------- .../java/com/google/cloud/spanner/Struct.java | 11 ++++------- .../google/cloud/spanner/StructReader.java | 12 ++++++------ .../java/com/google/cloud/spanner/Value.java | 12 ++++++------ .../connection/DirectExecuteResultSet.java | 14 +++++++------- .../ReplaceableForwardingResultSet.java | 14 +++++++------- .../AbstractStructReaderTypesTest.java | 8 ++++++++ .../protobuf/QueryProtoColumnSample.java | 8 +------- 11 files changed, 69 insertions(+), 74 deletions(-) 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 436ab62a0fb..f2e1a2dd2a4 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 @@ -55,8 +55,6 @@ import io.opencensus.trace.Tracing; import java.io.IOException; import java.io.Serializable; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; import java.math.BigDecimal; import java.util.AbstractList; import java.util.ArrayList; @@ -70,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; @@ -678,11 +677,9 @@ public T getProtoMessageInternal(int columnIndex, T } @Override - protected T getProtoEnumInternal(int columnIndex, - Class clazz) - throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { - Method parseMethod = clazz.getMethod("forNumber", int.class); - return clazz.cast(parseMethod.invoke(null, (int) getLongInternal(columnIndex))); + protected T getProtoEnumInternal( + int columnIndex, Function method) { + return (T) method.apply((int) getLongInternal(columnIndex)); } @Override @@ -1410,9 +1407,9 @@ protected T getProtoMessageInternal(int columnIndex, } @Override - protected T getProtoEnumInternal(int columnIndex, Class clazz) - throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { - return currRow().getProtoEnumInternal(columnIndex, clazz); + protected T getProtoEnumInternal( + int columnIndex, Function method) { + return currRow().getProtoEnumInternal(columnIndex, method); } @Override 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 23d0bb29d12..286edbc97c3 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 @@ -24,10 +24,10 @@ import com.google.protobuf.AbstractMessage; import com.google.protobuf.InvalidProtocolBufferException; import com.google.protobuf.ProtocolMessageEnum; -import java.lang.reflect.InvocationTargetException; import java.math.BigDecimal; import java.util.Arrays; import java.util.List; +import java.util.function.Function; /** * Base class for assisting {@link StructReader} implementations. @@ -67,9 +67,8 @@ protected String getPgJsonbInternal(int columnIndex) { protected abstract T getProtoMessageInternal(int columnIndex, T m) throws InvalidProtocolBufferException; - protected abstract T getProtoEnumInternal(int columnIndex, - Class clazz) - throws NoSuchMethodException, InvocationTargetException, IllegalAccessException; + protected abstract T getProtoEnumInternal( + int columnIndex, Function method); protected Value getValueInternal(int columnIndex) { throw new UnsupportedOperationException("method should be overwritten"); @@ -276,18 +275,18 @@ public byte[] getProtoMessage(String columnName) { } @Override - public T getProtoEnum(int columnIndex, Class clazz) - throws NoSuchMethodException, InvocationTargetException, IllegalAccessException{ + public T getProtoEnum( + int columnIndex, Function method) { checkNonNullOfType(columnIndex, Type.protoEnum(), columnIndex); - return getProtoEnumInternal(columnIndex, clazz); + return getProtoEnumInternal(columnIndex, method); } @Override - public T getProtoEnum(String columnName, Class clazz) - throws NoSuchMethodException, InvocationTargetException, IllegalAccessException{ + public T getProtoEnum( + String columnName, Function method) { int columnIndex = getColumnIndex(columnName); checkNonNullOfType(columnIndex, Type.proto(), columnName); - return getProtoEnumInternal(columnIndex, clazz); + return getProtoEnumInternal(columnIndex, method); } @Override 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 6e0261a4f90..fcc9112c48e 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 @@ -25,9 +25,9 @@ import com.google.protobuf.AbstractMessage; import com.google.protobuf.InvalidProtocolBufferException; import com.google.protobuf.ProtocolMessageEnum; -import java.lang.reflect.InvocationTargetException; import java.math.BigDecimal; import java.util.List; +import java.util.function.Function; /** Forwarding implements of StructReader */ public class ForwardingStructReader implements StructReader { @@ -413,17 +413,17 @@ public T getProtoMessage(String columnName, T m) } @Override - public T getProtoEnum(int columnIndex, Class clazz) - throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { + public T getProtoEnum( + int columnIndex, Function method) { checkValidState(); - return delegate.get().getProtoEnum(columnIndex, clazz); + return delegate.get().getProtoEnum(columnIndex, method); } @Override - public T getProtoEnum(String columnName, Class clazz) - throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { + public T getProtoEnum( + String columnName, Function method) { checkValidState(); - return delegate.get().getProtoEnum(columnName, clazz); + return delegate.get().getProtoEnum(columnName, method); } @Override 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 ccc229df10d..fe5626aa374 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 @@ -33,9 +33,9 @@ import com.google.protobuf.InvalidProtocolBufferException; import com.google.protobuf.ProtocolMessageEnum; import com.google.spanner.v1.ResultSetStats; -import java.lang.reflect.InvocationTargetException; 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 { @@ -320,15 +320,15 @@ public T getProtoMessage(String columnName, T m) } @Override - public T getProtoEnum(int columnIndex, Class clazz) - throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { - return getCurrentRowAsStruct().getProtoEnum(columnIndex, clazz); + public T getProtoEnum( + int columnIndex, Function method) { + return getCurrentRowAsStruct().getProtoEnum(columnIndex, method); } @Override - public T getProtoEnum(String columnName, Class clazz) - throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { - return getCurrentRowAsStruct().getProtoEnum(columnName, clazz); + public T getProtoEnum( + String columnName, Function method) { + return getCurrentRowAsStruct().getProtoEnum(columnName, method); } @Override 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 8e5b7ff3bda..5544e735e62 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 @@ -32,12 +32,11 @@ import com.google.protobuf.InvalidProtocolBufferException; import com.google.protobuf.ProtocolMessageEnum; import java.io.Serializable; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; 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; /** @@ -234,11 +233,9 @@ protected T getProtoMessageInternal(int columnIndex, } @Override - protected T getProtoEnumInternal(int columnIndex, - Class clazz) - throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { - Method parseMethod = clazz.getMethod("forNumber", int.class); - return clazz.cast(parseMethod.invoke(null, (int) values.get(columnIndex).getInt64())); + protected T getProtoEnumInternal( + int columnIndex, Function method) { + return (T) method.apply((int) values.get(columnIndex).getInt64()); } @Override 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 82241ff10dc..76abbe6106f 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 @@ -22,9 +22,9 @@ import com.google.protobuf.AbstractMessage; import com.google.protobuf.InvalidProtocolBufferException; import com.google.protobuf.ProtocolMessageEnum; -import java.lang.reflect.InvocationTargetException; 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 @@ -55,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 @@ -308,12 +309,11 @@ T getProtoMessage(int columnIndex, T m) T getProtoMessage(String columnName, T m) throws InvalidProtocolBufferException; - T getProtoEnum(int columnIndex, Class clazz) - throws NoSuchMethodException, InvocationTargetException, IllegalAccessException; - - T getProtoEnum(String columnName, Class clazz) - throws NoSuchMethodException, InvocationTargetException, IllegalAccessException; + 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/Value.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/Value.java index 2100038efc7..a8e2fd4dbbe 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 @@ -239,8 +239,8 @@ public static Value protoEnum(@Nullable long v) { return new ProtoEnumImpl(false, v); } - /**e - * Returns a {@code BYTES} value. Returns a {@code BYTES} value. + /** + * e Returns a {@code BYTES} value. Returns a {@code BYTES} value. * * @param v the value, which may be null */ @@ -567,8 +567,7 @@ byte[] getProtoMessage() { throw new UnsupportedOperationException("Not implemented"); } - public T getProtoMessage(T m) - throws InvalidProtocolBufferException { + public T getProtoMessage(T m) throws InvalidProtocolBufferException { throw new UnsupportedOperationException("Not implemented"); } @@ -1450,7 +1449,8 @@ void valueToString(StringBuilder b) { @Override com.google.protobuf.Value valueToProto() { - return com.google.protobuf.Value.newBuilder().setStringValue(Long.toString(value.enumValue)) + return com.google.protobuf.Value.newBuilder() + .setStringValue(Long.toString(value.enumValue)) .build(); } } @@ -2100,7 +2100,7 @@ private Value getValue(int fieldIndex) { case PROTO: return Value.protoMessage(value.getProtoMessage(fieldIndex)); case PROTO_ENUM: - return Value.protoEnum(value.getLong(fieldIndex)); + 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/connection/DirectExecuteResultSet.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/DirectExecuteResultSet.java index 4137b2c9def..e70706a11d8 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 @@ -29,9 +29,9 @@ import com.google.protobuf.InvalidProtocolBufferException; import com.google.protobuf.ProtocolMessageEnum; import com.google.spanner.v1.ResultSetStats; -import java.lang.reflect.InvocationTargetException; 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 @@ -448,17 +448,17 @@ public byte[] getProtoMessage(String columnName) { } @Override - public T getProtoEnum(int columnIndex, Class clazz) - throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { + public T getProtoEnum( + int columnIndex, Function method) { Preconditions.checkState(nextCalledByClient, MISSING_NEXT_CALL); - return delegate.getProtoEnum(columnIndex, clazz); + return delegate.getProtoEnum(columnIndex, method); } @Override - public T getProtoEnum(String columnName, Class clazz) - throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { + public T getProtoEnum( + String columnName, Function method) { Preconditions.checkState(nextCalledByClient, MISSING_NEXT_CALL); - return delegate.getProtoEnum(columnName, clazz); + return delegate.getProtoEnum(columnName, method); } @Override 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 7244ee89c76..9446502ffcf 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 @@ -31,9 +31,9 @@ import com.google.protobuf.InvalidProtocolBufferException; import com.google.protobuf.ProtocolMessageEnum; import com.google.spanner.v1.ResultSetStats; -import java.lang.reflect.InvocationTargetException; 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 @@ -467,16 +467,16 @@ public T getProtoMessage(String columnName, T m) } @Override - public T getProtoEnum(int columnIndex, Class clazz) - throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { + public T getProtoEnum( + int columnIndex, Function method) { checkClosed(); - return delegate.getProtoEnum(columnIndex, clazz); + return delegate.getProtoEnum(columnIndex, method); } @Override - public T getProtoEnum(String columnName, Class clazz) - throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { + public T getProtoEnum( + String columnName, Function method) { checkClosed(); - return delegate.getProtoEnum(columnName, clazz); + 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 a1e8b6474c7..75c10bcd194 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 @@ -28,6 +28,7 @@ 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; @@ -35,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; @@ -106,6 +108,12 @@ protected T getProtoMessageInternal(int columnIndex, return null; } + @Override + protected T getProtoEnumInternal( + int columnIndex, Function method) { + return null; + } + @Override protected Value getValueInternal(int columnIndex) { return null; 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 index fa2c644fa6d..fec008fae13 100644 --- a/samples/snippets/src/main/java/com/example/spanner/protobuf/QueryProtoColumnSample.java +++ b/samples/snippets/src/main/java/com/example/spanner/protobuf/QueryProtoColumnSample.java @@ -37,16 +37,10 @@ static void queryProtoColumn(DatabaseClient client) throws InvalidProtocolBuffer "bookId: %s, bookProto: %s, genre: %s %n", resultSet.getLong("bookId"), resultSet.getProtoMessage("bookProto", Book.getDefaultInstance()), - resultSet.getProtoEnum("genre", Genre.class)); + resultSet.getProtoEnum("genre", Genre::forNumber)); } } catch (InvalidProtocolBufferException e) { e.printStackTrace(); - } catch (InvocationTargetException e) { - e.printStackTrace(); - } catch (NoSuchMethodException e) { - e.printStackTrace(); - } catch (IllegalAccessException e) { - e.printStackTrace(); } } } From 2e400dd48503ea9b0f78101ee6f5bd88c38abb5e Mon Sep 17 00:00:00 2001 From: gauravpurohit Date: Thu, 29 Sep 2022 03:50:49 +0000 Subject: [PATCH 09/10] feat: Using pre-existing bytearray method from StructReader for serialized PROTO --- .../cloud/spanner/AbstractResultSet.java | 13 ++------ .../cloud/spanner/AbstractStructReader.java | 21 +++--------- .../cloud/spanner/ForwardingStructReader.java | 12 ------- .../com/google/cloud/spanner/ResultSets.java | 9 ----- .../java/com/google/cloud/spanner/Struct.java | 10 ++---- .../google/cloud/spanner/StructReader.java | 4 --- .../java/com/google/cloud/spanner/Value.java | 33 +++++++------------ .../spanner/connection/ChecksumResultSet.java | 4 +-- .../connection/DirectExecuteResultSet.java | 12 ------- .../ReplaceableForwardingResultSet.java | 12 ------- .../AbstractStructReaderTypesTest.java | 5 --- 11 files changed, 20 insertions(+), 115 deletions(-) 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 f2e1a2dd2a4..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 @@ -665,15 +665,11 @@ public boolean isNull(int columnIndex) { return rowData.get(columnIndex) == null; } - @Override - public byte[] getProtoMessageInternal(int columnIndex) { - return (byte[]) rowData.get(columnIndex); - } - @Override public T getProtoMessageInternal(int columnIndex, T m) throws InvalidProtocolBufferException { - return (T) m.toBuilder().mergeFrom(getProtoMessageInternal(columnIndex)).build(); + return (T) m.toBuilder().mergeFrom(((ByteArray) rowData.get(columnIndex)).toByteArray()) + .build(); } @Override @@ -1395,11 +1391,6 @@ protected String getStringInternal(int columnIndex) { return currRow().getStringInternal(columnIndex); } - @Override - protected byte[] getProtoMessageInternal(int columnIndex) { - return currRow().getProtoMessageInternal(columnIndex); - } - @Override protected T getProtoMessageInternal(int columnIndex, T m) throws InvalidProtocolBufferException { 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 286edbc97c3..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 @@ -62,8 +62,6 @@ protected String getPgJsonbInternal(int columnIndex) { protected abstract Date getDateInternal(int columnIndex); - protected abstract byte[] getProtoMessageInternal(int columnIndex); - protected abstract T getProtoMessageInternal(int columnIndex, T m) throws InvalidProtocolBufferException; @@ -224,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); } @@ -261,19 +261,6 @@ public Date getDate(String columnName) { return getDateInternal(columnIndex); } - @Override - public byte[] getProtoMessage(int columnIndex) { - checkNonNullOfType(columnIndex, Type.proto(), columnIndex); - return getProtoMessageInternal(columnIndex); - } - - @Override - public byte[] getProtoMessage(String columnName) { - int columnIndex = getColumnIndex(columnName); - checkNonNullOfType(columnIndex, Type.proto(), columnName); - return getProtoMessageInternal(columnIndex); - } - @Override public T getProtoEnum( int columnIndex, Function method) { 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 fcc9112c48e..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 @@ -386,18 +386,6 @@ public List getStructList(String columnName) { return delegate.get().getStructList(columnName); } - @Override - public byte[] getProtoMessage(int columnIndex) { - checkValidState(); - return delegate.get().getProtoMessage(columnIndex); - } - - @Override - public byte[] getProtoMessage(String columnName) { - checkValidState(); - return delegate.get().getProtoMessage(columnName); - } - @Override public T getProtoMessage(int columnIndex, T m) throws InvalidProtocolBufferException { 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 fe5626aa374..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 @@ -297,15 +297,6 @@ public Date getDate(String columnName) { return getCurrentRowAsStruct().getDate(columnName); } - @Override - public byte[] getProtoMessage(int columnIndex) { - return getCurrentRowAsStruct().getProtoMessage(columnIndex); - } - - @Override - public byte[] getProtoMessage(String columnName) { - return getCurrentRowAsStruct().getProtoMessage(columnName); - } @Override public T getProtoMessage(int columnIndex, T m) 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 5544e735e62..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 @@ -221,11 +221,6 @@ protected Date getDateInternal(int columnIndex) { return values.get(columnIndex).getDate(); } - @Override - protected byte[] getProtoMessageInternal(int columnIndex) { - return values.get(columnIndex).getProtoMessage(); - } - @Override protected T getProtoMessageInternal(int columnIndex, T m) throws InvalidProtocolBufferException { @@ -235,7 +230,7 @@ protected T getProtoMessageInternal(int columnIndex, @Override protected T getProtoEnumInternal( int columnIndex, Function method) { - return (T) method.apply((int) values.get(columnIndex).getInt64()); + return values.get(columnIndex).getProtoEnum(method); } @Override @@ -387,11 +382,10 @@ private Object getAsObject(int columnIndex) { return getStringInternal(columnIndex); case JSON: return getJsonInternal(columnIndex); - case PROTO: - return getProtoMessageInternal(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 76abbe6106f..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 @@ -299,10 +299,6 @@ 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); - byte[] getProtoMessage(int columnIndex); - - byte[] getProtoMessage(String columnName); - T getProtoMessage(int columnIndex, T m) throws InvalidProtocolBufferException; 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 a8e2fd4dbbe..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 @@ -31,8 +31,6 @@ import com.google.protobuf.NullValue; import com.google.protobuf.ProtocolMessageEnum; import java.io.Serializable; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; import java.math.BigDecimal; import java.util.ArrayList; import java.util.Arrays; @@ -41,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; @@ -563,16 +562,12 @@ public String getPgJsonb() { throw new UnsupportedOperationException("Not implemented"); } - byte[] getProtoMessage() { - throw new UnsupportedOperationException("Not implemented"); - } - public T getProtoMessage(T m) throws InvalidProtocolBufferException { throw new UnsupportedOperationException("Not implemented"); } - public T getProtoEnum(Class clazz) - throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { + public T getProtoEnum( + Function method) { throw new UnsupportedOperationException("Not implemented"); } @@ -886,11 +881,6 @@ public String getPgJsonb() { throw defaultGetter(Type.pgJsonb()); } - @Override - byte[] getProtoMessage() { - throw defaultGetter(Type.proto()); - } - @Override public T getProtoMessage(T m) throws InvalidProtocolBufferException { @@ -898,8 +888,8 @@ public T getProtoMessage(T m) } @Override - public T getProtoEnum(Class clazz) - throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { + public T getProtoEnum( + Function method) { throw defaultGetter(Type.protoEnum()); } @@ -1391,10 +1381,10 @@ private ProtoMessageImpl(boolean isNull, byte[] serializedProtoArray) { } @Override - byte[] getProtoMessage() { + public ByteArray getBytes() { checkType(Type.proto()); checkNotNull(); - return value.serializedMessage; + return ByteArray.copyFrom(value.serializedMessage); } @Override @@ -1434,12 +1424,11 @@ public long getInt64() { } @Override - public T getProtoEnum(Class clazz) - throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { + public T getProtoEnum( + Function method) { checkType(Type.protoEnum()); checkNotNull(); - Method parseMethod = clazz.getMethod("forNumber", int.class); - return clazz.cast(parseMethod.invoke(null, value.enumValue)); + return (T) method.apply((int) value.enumValue); } @Override @@ -2098,7 +2087,7 @@ private Value getValue(int fieldIndex) { case TIMESTAMP: return Value.timestamp(value.getTimestamp(fieldIndex)); case PROTO: - return Value.protoMessage(value.getProtoMessage(fieldIndex)); + return Value.protoMessage(value.getBytes(fieldIndex).toByteArray()); case PROTO_ENUM: return Value.protoEnum(value.getLong(fieldIndex)); case STRUCT: 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 4f0808b9631..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: @@ -249,9 +250,6 @@ public void funnel(Struct row, PrimitiveSink into) { case JSON: funnelValue(type, row.getJson(i), into); break; - case PROTO: - funnelValue(type, row.getProtoMessage(i), into); - break; case PG_JSONB: funnelValue(type, row.getPgJsonb(i), into); break; 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 e70706a11d8..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 @@ -435,18 +435,6 @@ public List getStructList(String columnName) { return delegate.getStructList(columnName); } - @Override - public byte[] getProtoMessage(int columnIndex) { - Preconditions.checkState(nextCalledByClient, MISSING_NEXT_CALL); - return delegate.getProtoMessage(columnIndex); - } - - @Override - public byte[] getProtoMessage(String columnName) { - Preconditions.checkState(nextCalledByClient, MISSING_NEXT_CALL); - return delegate.getProtoMessage(columnName); - } - @Override public T getProtoEnum( int columnIndex, Function method) { 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 9446502ffcf..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 @@ -440,18 +440,6 @@ public List getStructList(String columnName) { return delegate.getStructList(columnName); } - @Override - public byte[] getProtoMessage(int columnIndex) { - checkClosed(); - return delegate.getProtoMessage(columnIndex); - } - - @Override - public byte[] getProtoMessage(String columnName) { - checkClosed(); - return delegate.getProtoMessage(columnName); - } - @Override public T getProtoMessage(int columnIndex, T m) throws InvalidProtocolBufferException { 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 75c10bcd194..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 @@ -98,11 +98,6 @@ protected Date getDateInternal(int columnIndex) { return null; } - @Override - protected byte[] getProtoMessageInternal(int columnIndex) { - return null; - } - @Override protected T getProtoMessageInternal(int columnIndex, T m) { return null; From 7ae499a7da2f46754a2ba1689eec00799bfded68 Mon Sep 17 00:00:00 2001 From: gauravpurohit Date: Tue, 4 Oct 2022 13:36:48 +0000 Subject: [PATCH 10/10] feat: Using AbstractMessage instead of GenerateMessage for ValueBinder --- .../src/main/java/com/google/cloud/spanner/ValueBinder.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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 b8d266b7756..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,7 +19,7 @@ import com.google.cloud.ByteArray; import com.google.cloud.Date; import com.google.cloud.Timestamp; -import com.google.protobuf.GeneratedMessage; +import com.google.protobuf.AbstractMessage; import com.google.protobuf.ProtocolMessageEnum; import java.math.BigDecimal; import javax.annotation.Nullable; @@ -97,7 +97,7 @@ public R to(@Nullable String value) { return handle(Value.string(value)); } - public R to(@Nullable GeneratedMessage m) { + public R to(@Nullable AbstractMessage m) { return handle(Value.protoMessage(m)); }