From d612ce409cd493a4ccd2f531d3b032dbe7b581b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Knut=20Olav=20L=C3=B8ite?= Date: Fri, 10 Apr 2026 11:33:48 +0200 Subject: [PATCH] perf(spanner): reduce autoboxing when reading data AbstractStructReader and Struct contained multiple method definitions and calls that would trigger unnecessary object creation and auto-boxing on the happy path. This change removes those, sometimes at the expense of some duplicate code. This however reduces the number of object creations for the happy flow, which is by far the most used code path. --- .../cloud/spanner/AbstractStructReader.java | 317 +++++++++++------- .../java/com/google/cloud/spanner/Struct.java | 31 +- .../java/com/google/cloud/spanner/Type.java | 30 +- 3 files changed, 228 insertions(+), 150 deletions(-) diff --git a/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/AbstractStructReader.java b/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/AbstractStructReader.java index 60ff4fd330e6..9dc8690dc899 100644 --- a/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/AbstractStructReader.java +++ b/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/AbstractStructReader.java @@ -16,17 +16,14 @@ package com.google.cloud.spanner; -import static com.google.common.base.Preconditions.checkState; - import com.google.cloud.ByteArray; import com.google.cloud.Date; import com.google.cloud.Timestamp; import com.google.cloud.spanner.Type.Code; +import com.google.common.collect.ImmutableList; import com.google.protobuf.AbstractMessage; import com.google.protobuf.ProtocolMessageEnum; import java.math.BigDecimal; -import java.util.Arrays; -import java.util.Collections; import java.util.List; import java.util.UUID; import java.util.function.Function; @@ -40,6 +37,20 @@ * type appropriate for the method. */ public abstract class AbstractStructReader implements StructReader { + private static final ImmutableList VALID_LONG_TYPE_CODES = + ImmutableList.of(Code.ENUM, Code.PG_OID, Code.INT64); + private static final ImmutableList VALID_ENUM_TYPE_CODES = + ImmutableList.of(Code.ENUM, Code.INT64); + private static final ImmutableList VALID_BYTES_CODES = + ImmutableList.of(Code.PROTO, Code.BYTES); + private static final ImmutableList VALID_PROTO_CODES = + ImmutableList.of(Code.PROTO, Code.BYTES); + private static final ImmutableList VALID_STRING_TYPES = + ImmutableList.of(Type.string(), Type.pgNumeric()); + private static final ImmutableList VALID_ARRAY_CODES = ImmutableList.of(Code.ARRAY); + private static final ImmutableList VALID_STRING_ARRAY_TYPES = + ImmutableList.of(Type.TYPE_ARRAY_STRING, Type.TYPE_ARRAY_PG_NUMERIC); + protected abstract boolean getBooleanInternal(int columnIndex); protected abstract long getLongInternal(int columnIndex); @@ -169,7 +180,7 @@ public boolean isNull(String columnName) { @Override public boolean getBoolean(int columnIndex) { - checkNonNullOfType(columnIndex, Type.bool(), columnIndex); + checkNonNullOfType(columnIndex, Type.bool()); return getBooleanInternal(columnIndex); } @@ -182,21 +193,20 @@ public boolean getBoolean(String columnName) { @Override public long getLong(int columnIndex) { - checkNonNullOfCodes( - columnIndex, Arrays.asList(Code.ENUM, Code.PG_OID, Code.INT64), columnIndex); + checkNonNullOfCodes(columnIndex, VALID_LONG_TYPE_CODES); return getLongInternal(columnIndex); } @Override public long getLong(String columnName) { int columnIndex = getColumnIndex(columnName); - checkNonNullOfCodes(columnIndex, Arrays.asList(Code.ENUM, Code.PG_OID, Code.INT64), columnName); + checkNonNullOfCodes(columnIndex, VALID_LONG_TYPE_CODES, columnName); return getLongInternal(columnIndex); } @Override public float getFloat(int columnIndex) { - checkNonNullOfType(columnIndex, Type.float32(), columnIndex); + checkNonNullOfType(columnIndex, Type.float32()); return getFloatInternal(columnIndex); } @@ -209,7 +219,7 @@ public float getFloat(String columnName) { @Override public double getDouble(int columnIndex) { - checkNonNullOfType(columnIndex, Type.float64(), columnIndex); + checkNonNullOfType(columnIndex, Type.float64()); return getDoubleInternal(columnIndex); } @@ -222,7 +232,7 @@ public double getDouble(String columnName) { @Override public BigDecimal getBigDecimal(int columnIndex) { - checkNonNullOfType(columnIndex, Type.numeric(), columnIndex); + checkNonNullOfType(columnIndex, Type.numeric()); return getBigDecimalInternal(columnIndex); } @@ -235,25 +245,20 @@ public BigDecimal getBigDecimal(String columnName) { @Override public String getString(int columnIndex) { - checkNonNullOfTypes( - columnIndex, - Arrays.asList(Type.string(), Type.pgNumeric()), - columnIndex, - "STRING, NUMERIC"); + checkNonNullOfTypes(columnIndex, VALID_STRING_TYPES, "STRING, NUMERIC"); return getStringInternal(columnIndex); } @Override public String getString(String columnName) { int columnIndex = getColumnIndex(columnName); - checkNonNullOfTypes( - columnIndex, Arrays.asList(Type.string(), Type.pgNumeric()), columnName, "STRING, NUMERIC"); + checkNonNullOfTypes(columnIndex, VALID_STRING_TYPES, columnName, "STRING, NUMERIC"); return getStringInternal(columnIndex); } @Override public String getJson(int columnIndex) { - checkNonNullOfType(columnIndex, Type.json(), columnIndex); + checkNonNullOfType(columnIndex, Type.json()); return getJsonInternal(columnIndex); } @@ -266,7 +271,7 @@ public String getJson(String columnName) { @Override public String getPgJsonb(int columnIndex) { - checkNonNullOfType(columnIndex, Type.pgJsonb(), columnIndex); + checkNonNullOfType(columnIndex, Type.pgJsonb()); return getPgJsonbInternal(columnIndex); } @@ -279,20 +284,20 @@ public String getPgJsonb(String columnName) { @Override public ByteArray getBytes(int columnIndex) { - checkNonNullOfCodes(columnIndex, Arrays.asList(Code.PROTO, Code.BYTES), columnIndex); + checkNonNullOfCodes(columnIndex, VALID_BYTES_CODES); return getBytesInternal(columnIndex); } @Override public ByteArray getBytes(String columnName) { int columnIndex = getColumnIndex(columnName); - checkNonNullOfCodes(columnIndex, Arrays.asList(Code.PROTO, Code.BYTES), columnName); + checkNonNullOfCodes(columnIndex, VALID_BYTES_CODES, columnName); return getBytesInternal(columnIndex); } @Override public Timestamp getTimestamp(int columnIndex) { - checkNonNullOfType(columnIndex, Type.timestamp(), columnIndex); + checkNonNullOfType(columnIndex, Type.timestamp()); return getTimestampInternal(columnIndex); } @@ -305,7 +310,7 @@ public Timestamp getTimestamp(String columnName) { @Override public Date getDate(int columnIndex) { - checkNonNullOfType(columnIndex, Type.date(), columnIndex); + checkNonNullOfType(columnIndex, Type.date()); return getDateInternal(columnIndex); } @@ -318,7 +323,7 @@ public Date getDate(String columnName) { @Override public UUID getUuid(int columnIndex) { - checkNonNullOfType(columnIndex, Type.uuid(), columnIndex); + checkNonNullOfType(columnIndex, Type.uuid()); return getUuidInternal(columnIndex); } @@ -331,7 +336,7 @@ public UUID getUuid(String columnName) { @Override public Interval getInterval(int columnIndex) { - checkNonNullOfType(columnIndex, Type.interval(), columnIndex); + checkNonNullOfType(columnIndex, Type.interval()); return getIntervalInternal(columnIndex); } @@ -345,7 +350,7 @@ public Interval getInterval(String columnName) { @Override public T getProtoEnum( int columnIndex, Function method) { - checkNonNullOfCodes(columnIndex, Arrays.asList(Code.ENUM, Code.INT64), columnIndex); + checkNonNullOfCodes(columnIndex, VALID_ENUM_TYPE_CODES); return getProtoEnumInternal(columnIndex, method); } @@ -353,20 +358,20 @@ public T getProtoEnum( public T getProtoEnum( String columnName, Function method) { int columnIndex = getColumnIndex(columnName); - checkNonNullOfCodes(columnIndex, Arrays.asList(Code.ENUM, Code.INT64), columnName); + checkNonNullOfCodes(columnIndex, VALID_ENUM_TYPE_CODES, columnName); return getProtoEnumInternal(columnIndex, method); } @Override public T getProtoMessage(int columnIndex, T message) { - checkNonNullOfCodes(columnIndex, Arrays.asList(Code.PROTO, Code.BYTES), columnIndex); + checkNonNullOfCodes(columnIndex, VALID_PROTO_CODES); return getProtoMessageInternal(columnIndex, message); } @Override public T getProtoMessage(String columnName, T message) { int columnIndex = getColumnIndex(columnName); - checkNonNullOfCodes(columnIndex, Arrays.asList(Code.PROTO, Code.BYTES), columnName); + checkNonNullOfCodes(columnIndex, VALID_PROTO_CODES, columnName); return getProtoMessageInternal(columnIndex, message); } @@ -383,136 +388,128 @@ public Value getValue(String columnName) { @Override public boolean[] getBooleanArray(int columnIndex) { - checkNonNullOfType(columnIndex, Type.array(Type.bool()), columnIndex); + checkNonNullOfType(columnIndex, Type.TYPE_ARRAY_BOOL); return getBooleanArrayInternal(columnIndex); } @Override public boolean[] getBooleanArray(String columnName) { int columnIndex = getColumnIndex(columnName); - checkNonNullOfType(columnIndex, Type.array(Type.bool()), columnName); + checkNonNullOfType(columnIndex, Type.TYPE_ARRAY_BOOL, columnName); return getBooleanArrayInternal(columnIndex); } @Override public List getBooleanList(int columnIndex) { - checkNonNullOfType(columnIndex, Type.array(Type.bool()), columnIndex); + checkNonNullOfType(columnIndex, Type.TYPE_ARRAY_BOOL); return getBooleanListInternal(columnIndex); } @Override public List getBooleanList(String columnName) { int columnIndex = getColumnIndex(columnName); - checkNonNullOfType(columnIndex, Type.array(Type.bool()), columnName); + checkNonNullOfType(columnIndex, Type.TYPE_ARRAY_BOOL, columnName); return getBooleanListInternal(columnIndex); } @Override public long[] getLongArray(int columnIndex) { - checkNonNullOfCodes(columnIndex, Collections.singletonList(Code.ARRAY), columnIndex); - checkArrayElementType( - columnIndex, Arrays.asList(Code.ENUM, Code.PG_OID, Code.INT64), columnIndex); + checkNonNullOfCodes(columnIndex, VALID_ARRAY_CODES); + checkArrayElementType(columnIndex, VALID_LONG_TYPE_CODES); return getLongArrayInternal(columnIndex); } @Override public long[] getLongArray(String columnName) { int columnIndex = getColumnIndex(columnName); - checkNonNullOfCodes(columnIndex, Collections.singletonList(Code.ARRAY), columnName); - checkArrayElementType( - columnIndex, Arrays.asList(Code.ENUM, Code.PG_OID, Code.INT64), columnName); + checkNonNullOfCodes(columnIndex, VALID_ARRAY_CODES, columnName); + checkArrayElementType(columnIndex, VALID_LONG_TYPE_CODES, columnName); return getLongArrayInternal(columnIndex); } @Override public List getLongList(int columnIndex) { - checkNonNullOfCodes(columnIndex, Collections.singletonList(Code.ARRAY), columnIndex); - checkArrayElementType( - columnIndex, Arrays.asList(Code.ENUM, Code.PG_OID, Code.INT64), columnIndex); + checkNonNullOfCodes(columnIndex, VALID_ARRAY_CODES); + checkArrayElementType(columnIndex, VALID_LONG_TYPE_CODES); return getLongListInternal(columnIndex); } @Override public List getLongList(String columnName) { int columnIndex = getColumnIndex(columnName); - checkNonNullOfCodes(columnIndex, Collections.singletonList(Code.ARRAY), columnName); - checkArrayElementType( - columnIndex, Arrays.asList(Code.ENUM, Code.PG_OID, Code.INT64), columnName); + checkNonNullOfCodes(columnIndex, VALID_ARRAY_CODES, columnName); + checkArrayElementType(columnIndex, VALID_LONG_TYPE_CODES, columnName); return getLongListInternal(columnIndex); } @Override public float[] getFloatArray(int columnIndex) { - checkNonNullOfType(columnIndex, Type.array(Type.float32()), columnIndex); + checkNonNullOfType(columnIndex, Type.TYPE_ARRAY_FLOAT32); return getFloatArrayInternal(columnIndex); } @Override public float[] getFloatArray(String columnName) { int columnIndex = getColumnIndex(columnName); - checkNonNullOfType(columnIndex, Type.array(Type.float32()), columnName); + checkNonNullOfType(columnIndex, Type.TYPE_ARRAY_FLOAT32, columnName); return getFloatArrayInternal(columnIndex); } @Override public List getFloatList(int columnIndex) { - checkNonNullOfType(columnIndex, Type.array(Type.float32()), columnIndex); + checkNonNullOfType(columnIndex, Type.TYPE_ARRAY_FLOAT32); return getFloatListInternal(columnIndex); } @Override public List getFloatList(String columnName) { int columnIndex = getColumnIndex(columnName); - checkNonNullOfType(columnIndex, Type.array(Type.float32()), columnName); + checkNonNullOfType(columnIndex, Type.TYPE_ARRAY_FLOAT32, columnName); return getFloatListInternal(columnIndex); } @Override public double[] getDoubleArray(int columnIndex) { - checkNonNullOfType(columnIndex, Type.array(Type.float64()), columnIndex); + checkNonNullOfType(columnIndex, Type.TYPE_ARRAY_FLOAT64); return getDoubleArrayInternal(columnIndex); } @Override public double[] getDoubleArray(String columnName) { int columnIndex = getColumnIndex(columnName); - checkNonNullOfType(columnIndex, Type.array(Type.float64()), columnName); + checkNonNullOfType(columnIndex, Type.TYPE_ARRAY_FLOAT64, columnName); return getDoubleArrayInternal(columnIndex); } @Override public List getDoubleList(int columnIndex) { - checkNonNullOfType(columnIndex, Type.array(Type.float64()), columnIndex); + checkNonNullOfType(columnIndex, Type.TYPE_ARRAY_FLOAT64); return getDoubleListInternal(columnIndex); } @Override public List getDoubleList(String columnName) { int columnIndex = getColumnIndex(columnName); - checkNonNullOfType(columnIndex, Type.array(Type.float64()), columnName); + checkNonNullOfType(columnIndex, Type.TYPE_ARRAY_FLOAT64, columnName); return getDoubleListInternal(columnIndex); } @Override public List getBigDecimalList(int columnIndex) { - checkNonNullOfType(columnIndex, Type.array(Type.numeric()), columnIndex); + checkNonNullOfType(columnIndex, Type.TYPE_ARRAY_NUMERIC); return getBigDecimalListInternal(columnIndex); } @Override public List getBigDecimalList(String columnName) { int columnIndex = getColumnIndex(columnName); - checkNonNullOfType(columnIndex, Type.array(Type.numeric()), columnName); + checkNonNullOfType(columnIndex, Type.TYPE_ARRAY_NUMERIC, columnName); return getBigDecimalListInternal(columnIndex); } @Override public List getStringList(int columnIndex) { - checkNonNullOfTypes( - columnIndex, - Arrays.asList(Type.array(Type.string()), Type.array(Type.pgNumeric())), - columnIndex, - "ARRAY, ARRAY"); + checkNonNullOfTypes(columnIndex, VALID_STRING_ARRAY_TYPES, "ARRAY, ARRAY"); return getStringListInternal(columnIndex); } @@ -520,74 +517,71 @@ public List getStringList(int columnIndex) { public List getStringList(String columnName) { int columnIndex = getColumnIndex(columnName); checkNonNullOfTypes( - columnIndex, - Arrays.asList(Type.array(Type.string()), Type.array(Type.pgNumeric())), - columnName, - "ARRAY, ARRAY"); + columnIndex, VALID_STRING_ARRAY_TYPES, columnName, "ARRAY, ARRAY"); return getStringListInternal(columnIndex); } @Override public List getJsonList(int columnIndex) { - checkNonNullOfType(columnIndex, Type.array(Type.json()), columnIndex); + checkNonNullOfType(columnIndex, Type.TYPE_ARRAY_JSON); return getJsonListInternal(columnIndex); } @Override public List getJsonList(String columnName) { int columnIndex = getColumnIndex(columnName); - checkNonNullOfType(columnIndex, Type.array(Type.json()), columnName); + checkNonNullOfType(columnIndex, Type.TYPE_ARRAY_JSON, columnName); return getJsonListInternal(columnIndex); } @Override public List getPgJsonbList(int columnIndex) { - checkNonNullOfType(columnIndex, Type.array(Type.pgJsonb()), columnIndex); + checkNonNullOfType(columnIndex, Type.TYPE_ARRAY_PG_JSONB); return getPgJsonbListInternal(columnIndex); } @Override public List getPgJsonbList(String columnName) { int columnIndex = getColumnIndex(columnName); - checkNonNullOfType(columnIndex, Type.array(Type.pgJsonb()), columnName); + checkNonNullOfType(columnIndex, Type.TYPE_ARRAY_PG_JSONB, columnName); return getPgJsonbListInternal(columnIndex); } @Override public List getBytesList(int columnIndex) { - checkNonNullOfCodes(columnIndex, Collections.singletonList(Code.ARRAY), columnIndex); - checkArrayElementType(columnIndex, Arrays.asList(Code.PROTO, Code.BYTES), columnIndex); + checkNonNullOfCodes(columnIndex, VALID_ARRAY_CODES); + checkArrayElementType(columnIndex, VALID_PROTO_CODES); return getBytesListInternal(columnIndex); } @Override public List getBytesList(String columnName) { int columnIndex = getColumnIndex(columnName); - checkNonNullOfCodes(columnIndex, Collections.singletonList(Code.ARRAY), columnName); - checkArrayElementType(columnIndex, Arrays.asList(Code.PROTO, Code.BYTES), columnName); + checkNonNullOfCodes(columnIndex, VALID_ARRAY_CODES, columnName); + checkArrayElementType(columnIndex, VALID_PROTO_CODES, columnName); return getBytesListInternal(columnIndex); } @Override public List getProtoMessageList(int columnIndex, T message) { - checkNonNullOfCodes(columnIndex, Collections.singletonList(Code.ARRAY), columnIndex); - checkArrayElementType(columnIndex, Arrays.asList(Code.PROTO, Code.BYTES), columnIndex); + checkNonNullOfCodes(columnIndex, VALID_ARRAY_CODES); + checkArrayElementType(columnIndex, VALID_PROTO_CODES); return getProtoMessageListInternal(columnIndex, message); } @Override public List getProtoMessageList(String columnName, T message) { int columnIndex = getColumnIndex(columnName); - checkNonNullOfCodes(columnIndex, Collections.singletonList(Code.ARRAY), columnName); - checkArrayElementType(columnIndex, Arrays.asList(Code.PROTO, Code.BYTES), columnName); + checkNonNullOfCodes(columnIndex, VALID_ARRAY_CODES, columnName); + checkArrayElementType(columnIndex, VALID_PROTO_CODES, columnName); return getProtoMessageListInternal(columnIndex, message); } @Override public List getProtoEnumList( int columnIndex, Function method) { - checkNonNullOfCodes(columnIndex, Collections.singletonList(Code.ARRAY), columnIndex); - checkArrayElementType(columnIndex, Arrays.asList(Code.ENUM, Code.INT64), columnIndex); + checkNonNullOfCodes(columnIndex, VALID_ARRAY_CODES); + checkArrayElementType(columnIndex, VALID_ENUM_TYPE_CODES); return getProtoEnumListInternal(columnIndex, method); } @@ -595,66 +589,66 @@ public List getProtoEnumList( public List getProtoEnumList( String columnName, Function method) { int columnIndex = getColumnIndex(columnName); - checkNonNullOfCodes(columnIndex, Collections.singletonList(Code.ARRAY), columnName); - checkArrayElementType(columnIndex, Arrays.asList(Code.ENUM, Code.INT64), columnName); + checkNonNullOfCodes(columnIndex, VALID_ARRAY_CODES, columnName); + checkArrayElementType(columnIndex, VALID_ENUM_TYPE_CODES, columnName); return getProtoEnumListInternal(columnIndex, method); } @Override public List getTimestampList(int columnIndex) { - checkNonNullOfType(columnIndex, Type.array(Type.timestamp()), columnIndex); + checkNonNullOfType(columnIndex, Type.TYPE_ARRAY_TIMESTAMP); return getTimestampListInternal(columnIndex); } @Override public List getTimestampList(String columnName) { int columnIndex = getColumnIndex(columnName); - checkNonNullOfType(columnIndex, Type.array(Type.timestamp()), columnName); + checkNonNullOfType(columnIndex, Type.TYPE_ARRAY_TIMESTAMP, columnName); return getTimestampListInternal(columnIndex); } @Override public List getDateList(int columnIndex) { - checkNonNullOfType(columnIndex, Type.array(Type.date()), columnIndex); + checkNonNullOfType(columnIndex, Type.TYPE_ARRAY_DATE); return getDateListInternal(columnIndex); } @Override public List getDateList(String columnName) { int columnIndex = getColumnIndex(columnName); - checkNonNullOfType(columnIndex, Type.array(Type.date()), columnName); + checkNonNullOfType(columnIndex, Type.TYPE_ARRAY_DATE, columnName); return getDateListInternal(columnIndex); } @Override public List getUuidList(int columnIndex) { - checkNonNullOfType(columnIndex, Type.array(Type.uuid()), columnIndex); + checkNonNullOfType(columnIndex, Type.TYPE_ARRAY_UUID); return getUuidListInternal(columnIndex); } @Override public List getUuidList(String columnName) { final int columnIndex = getColumnIndex(columnName); - checkNonNullOfType(columnIndex, Type.array(Type.uuid()), columnName); + checkNonNullOfType(columnIndex, Type.TYPE_ARRAY_UUID, columnName); return getUuidListInternal(columnIndex); } @Override public List getIntervalList(int columnIndex) { - checkNonNullOfType(columnIndex, Type.array(Type.interval()), columnIndex); + checkNonNullOfType(columnIndex, Type.TYPE_ARRAY_INTERVAL); return getIntervalListInternal(columnIndex); } @Override public List getIntervalList(String columnName) { int columnIndex = getColumnIndex(columnName); - checkNonNullOfType(columnIndex, Type.array(Type.interval()), columnName); + checkNonNullOfType(columnIndex, Type.TYPE_ARRAY_INTERVAL, columnName); return getIntervalListInternal(columnIndex); } @Override public List getStructList(int columnIndex) { - checkNonNullArrayOfStruct(columnIndex, columnIndex); + checkNonNullArrayOfStruct(columnIndex); return getStructListInternal(columnIndex); } @@ -674,70 +668,141 @@ public int getColumnIndex(String columnName) { return getType().getFieldIndex(columnName); } - protected void checkNonNull(int columnIndex, Object columnNameForError) { + protected void checkNonNull(int columnIndex, String columnNameForError) { if (isNull(columnIndex)) { throw new NullPointerException("Column " + columnNameForError + " contains NULL value"); } } - private void checkNonNullOfType(int columnIndex, Type expectedType, Object columnNameForError) { + /** + * @deprecated use {@link #checkNonNull(int, String)} instead. + */ + @Deprecated + protected void checkNonNull(int columnIndex, Object columnNameForError) { + checkNonNull(columnIndex, String.valueOf(columnNameForError)); + } + + protected void checkNonNull(int columnIndex) { + if (isNull(columnIndex)) { + throw new NullPointerException("Column " + columnIndex + " contains NULL value"); + } + } + + private void checkNonNullOfType(int columnIndex, Type expectedType, String columnNameForError) { Type actualType = getColumnType(columnIndex); - checkState( - expectedType.equals(actualType), - "Column %s is not of correct type: expected %s but was %s", - columnNameForError, - expectedType, - actualType); + if (!expectedType.equals(actualType)) { + throw new IllegalStateException( + String.format( + "Column %s is not of correct type: expected %s but was %s", + columnNameForError, expectedType, actualType)); + } checkNonNull(columnIndex, columnNameForError); } + private void checkNonNullOfType(int columnIndex, Type expectedType) { + Type actualType = getColumnType(columnIndex); + if (!expectedType.equals(actualType)) { + throw new IllegalStateException( + String.format( + "Column %d is not of correct type: expected %s but was %s", + columnIndex, expectedType, actualType)); + } + checkNonNull(columnIndex); + } + /** Checks if the value at {@code columnIndex} is one of {@code expectedCode} */ private void checkNonNullOfCodes( - int columnIndex, List expectedCodes, Object columnNameForError) { + int columnIndex, List expectedCodes, String columnNameForError) { Type actualType = getColumnType(columnIndex); - checkState( - expectedCodes.contains(actualType.getCode()), - "Column %s is not of correct type code: expected one of [%s] but was %s", - columnNameForError, - expectedCodes, - actualType); + if (!expectedCodes.contains(actualType.getCode())) { + throw new IllegalStateException( + String.format( + "Column %s is not of correct type code: expected one of [%s] but was %s", + columnNameForError, expectedCodes, actualType)); + } checkNonNull(columnIndex, columnNameForError); } + private void checkNonNullOfCodes(int columnIndex, List expectedCodes) { + Type actualType = getColumnType(columnIndex); + if (!expectedCodes.contains(actualType.getCode())) { + throw new IllegalStateException( + String.format( + "Column %d is not of correct type code: expected one of [%s] but was %s", + columnIndex, expectedCodes, actualType)); + } + checkNonNull(columnIndex); + } + private void checkArrayElementType( - int columnIndex, List expectedCodes, Object columnNameForError) { + int columnIndex, List expectedCodes, String columnNameForError) { + Type arrayElementType = getColumnType(columnIndex).getArrayElementType(); + if (!expectedCodes.contains(arrayElementType.getCode())) { + throw new IllegalStateException( + String.format( + "Array element for Column %s is not of correct type code: expected one of [%s] but was %s", + columnNameForError, expectedCodes, Type.array(arrayElementType))); + } + } + + private void checkArrayElementType(int columnIndex, List expectedCodes) { Type arrayElementType = getColumnType(columnIndex).getArrayElementType(); - checkState( - expectedCodes.contains(arrayElementType.getCode()), - "Array element for Column %s is not of correct type code: expected one of [%s] but was %s", - columnNameForError, - expectedCodes, - Type.array(arrayElementType)); + if (!expectedCodes.contains(arrayElementType.getCode())) { + throw new IllegalStateException( + String.format( + "Array element for Column %d is not of correct type code: expected one of [%s] but was %s", + columnIndex, expectedCodes, Type.array(arrayElementType))); + } } private void checkNonNullOfTypes( int columnIndex, List expectedTypes, - Object columnNameForError, + String columnNameForError, String expectedTypeNames) { Type actualType = getColumnType(columnIndex); - checkState( - expectedTypes.contains(actualType), - "Column %s is not of correct type: expected one of [%s] but was %s", - columnNameForError, - expectedTypeNames, - actualType); + if (!expectedTypes.contains(actualType)) { + throw new IllegalStateException( + String.format( + "Column %s is not of correct type: expected one of [%s] but was %s", + columnNameForError, expectedTypeNames, actualType)); + } checkNonNull(columnIndex, columnNameForError); } - private void checkNonNullArrayOfStruct(int columnIndex, Object columnNameForError) { + private void checkNonNullOfTypes( + int columnIndex, List expectedTypes, String expectedTypeNames) { Type actualType = getColumnType(columnIndex); - checkState( - actualType.getCode() == Type.Code.ARRAY - && actualType.getArrayElementType().getCode() == Type.Code.STRUCT, - "Column %s is not of correct type: expected ARRAY> but was %s", - columnNameForError, - actualType); + if (!expectedTypes.contains(actualType)) { + throw new IllegalStateException( + String.format( + "Column %d is not of correct type: expected one of [%s] but was %s", + columnIndex, expectedTypeNames, actualType)); + } + checkNonNull(columnIndex); + } + + private void checkNonNullArrayOfStruct(int columnIndex, String columnNameForError) { + Type actualType = getColumnType(columnIndex); + if (actualType.getCode() != Type.Code.ARRAY + || actualType.getArrayElementType().getCode() != Type.Code.STRUCT) { + throw new IllegalStateException( + String.format( + "Column %s is not of correct type: expected ARRAY> but was %s", + columnNameForError, actualType)); + } checkNonNull(columnIndex, columnNameForError); } + + private void checkNonNullArrayOfStruct(int columnIndex) { + Type actualType = getColumnType(columnIndex); + if (actualType.getCode() != Type.Code.ARRAY + || actualType.getArrayElementType().getCode() != Type.Code.STRUCT) { + throw new IllegalStateException( + String.format( + "Column %d is not of correct type: expected ARRAY> but was %s", + columnIndex, actualType)); + } + checkNonNull(columnIndex); + } } diff --git a/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/Struct.java b/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/Struct.java index 38a47e99dffe..b597e02cda48 100644 --- a/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/Struct.java +++ b/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/Struct.java @@ -17,7 +17,6 @@ package com.google.cloud.spanner; import static com.google.common.base.Preconditions.checkNotNull; -import static com.google.common.base.Preconditions.checkState; import com.google.cloud.ByteArray; import com.google.cloud.Date; @@ -125,7 +124,9 @@ private void addInternal(String fieldName, Value value) { private void checkBindingInProgress(boolean expectInProgress) { if (expectInProgress) { - checkState(currentField != null, "No binding currently active"); + if (currentField == null) { + throw new IllegalStateException("No binding currently active"); + } } else if (currentField != null) { throw new IllegalStateException("Incomplete binding for column " + currentField); } @@ -139,7 +140,7 @@ private void checkBindingInProgress(boolean expectInProgress) { /* Public methods for accessing struct-typed fields */ public Struct getStruct(int columnIndex) { - checkNonNullStruct(columnIndex, columnIndex); + checkNonNullStruct(columnIndex); return getStructInternal(columnIndex); } @@ -152,16 +153,28 @@ public Struct getStruct(String columnName) { /* Sub-classes must implement this method */ protected abstract Struct getStructInternal(int columnIndex); - private void checkNonNullStruct(int columnIndex, Object columnNameForError) { + private void checkNonNullStruct(int columnIndex, String columnNameForError) { Type actualType = getColumnType(columnIndex); - checkState( - actualType.getCode() == Code.STRUCT, - "Column %s is not of correct type: expected STRUCT<...> but was %s", - columnNameForError, - actualType); + if (actualType.getCode() != Code.STRUCT) { + throw new IllegalStateException( + String.format( + "Column %s is not of correct type: expected STRUCT<...> but was %s", + columnNameForError, actualType)); + } checkNonNull(columnIndex, columnNameForError); } + private void checkNonNullStruct(int columnIndex) { + Type actualType = getColumnType(columnIndex); + if (actualType.getCode() != Code.STRUCT) { + throw new IllegalStateException( + String.format( + "Column %d is not of correct type: expected STRUCT<...> but was %s", + columnIndex, actualType)); + } + checkNonNull(columnIndex); + } + /** Default implementation for value structs produced by {@link Builder}. */ private static class ValueListStruct extends Struct { private final Type type; diff --git a/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/Type.java b/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/Type.java index 71120a0f420f..4a22505350f4 100644 --- a/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/Type.java +++ b/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/Type.java @@ -61,21 +61,21 @@ public final class Type implements Serializable { private static final Type TYPE_DATE = new Type(Code.DATE, null, null); private static final Type TYPE_UUID = new Type(Code.UUID, null, null); private static final Type TYPE_INTERVAL = new Type(Code.INTERVAL, 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_FLOAT32 = new Type(Code.ARRAY, TYPE_FLOAT32, null); - private static final Type TYPE_ARRAY_FLOAT64 = new Type(Code.ARRAY, TYPE_FLOAT64, null); - private static final Type TYPE_ARRAY_NUMERIC = new Type(Code.ARRAY, TYPE_NUMERIC, null); - private static final Type TYPE_ARRAY_PG_NUMERIC = new Type(Code.ARRAY, TYPE_PG_NUMERIC, null); - 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_PG_OID = new Type(Code.ARRAY, TYPE_PG_OID, 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); - private static final Type TYPE_ARRAY_UUID = new Type(Code.ARRAY, TYPE_UUID, null); - private static final Type TYPE_ARRAY_INTERVAL = new Type(Code.ARRAY, TYPE_INTERVAL, null); + static final Type TYPE_ARRAY_BOOL = new Type(Code.ARRAY, TYPE_BOOL, null); + static final Type TYPE_ARRAY_INT64 = new Type(Code.ARRAY, TYPE_INT64, null); + static final Type TYPE_ARRAY_FLOAT32 = new Type(Code.ARRAY, TYPE_FLOAT32, null); + static final Type TYPE_ARRAY_FLOAT64 = new Type(Code.ARRAY, TYPE_FLOAT64, null); + static final Type TYPE_ARRAY_NUMERIC = new Type(Code.ARRAY, TYPE_NUMERIC, null); + static final Type TYPE_ARRAY_PG_NUMERIC = new Type(Code.ARRAY, TYPE_PG_NUMERIC, null); + static final Type TYPE_ARRAY_STRING = new Type(Code.ARRAY, TYPE_STRING, null); + static final Type TYPE_ARRAY_JSON = new Type(Code.ARRAY, TYPE_JSON, null); + static final Type TYPE_ARRAY_PG_JSONB = new Type(Code.ARRAY, TYPE_PG_JSONB, null); + static final Type TYPE_ARRAY_PG_OID = new Type(Code.ARRAY, TYPE_PG_OID, null); + static final Type TYPE_ARRAY_BYTES = new Type(Code.ARRAY, TYPE_BYTES, null); + static final Type TYPE_ARRAY_TIMESTAMP = new Type(Code.ARRAY, TYPE_TIMESTAMP, null); + static final Type TYPE_ARRAY_DATE = new Type(Code.ARRAY, TYPE_DATE, null); + static final Type TYPE_ARRAY_UUID = new Type(Code.ARRAY, TYPE_UUID, null); + static final Type TYPE_ARRAY_INTERVAL = new Type(Code.ARRAY, TYPE_INTERVAL, null); private static final int AMBIGUOUS_FIELD = -1; private static final long serialVersionUID = -3076152125004114582L;