diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml
index 4fe5683..1523cd9 100644
--- a/.github/workflows/build.yaml
+++ b/.github/workflows/build.yaml
@@ -36,7 +36,7 @@ jobs:
- name: Setup Java JDK
uses: actions/setup-java@v1
with:
- java-version: 17
+ java-version: 18
- name: Install with maven
env:
JAVA_TOOL_OPTIONS: ${{ matrix.java-opts }}
diff --git a/.github/workflows/codacy-coverage-reporter.yml b/.github/workflows/codacy-coverage-reporter.yml
index 566686e..b6c4919 100644
--- a/.github/workflows/codacy-coverage-reporter.yml
+++ b/.github/workflows/codacy-coverage-reporter.yml
@@ -15,7 +15,7 @@ jobs:
- name: Setup Java JDK
uses: actions/setup-java@v1
with:
- java-version: 17
+ java-version: 18
- name: Verify with maven
env:
JAVA_TOOL_OPTIONS: "-Djava.awt.headless=true -Dtestfx.robot=glass -Dtestfx.headless=true -Dprism.order=sw -Dprism.text=t2k"
diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml
index 05758c6..5023f35 100644
--- a/.github/workflows/codeql-analysis.yml
+++ b/.github/workflows/codeql-analysis.yml
@@ -32,7 +32,7 @@ jobs:
- name: Setup Java JDK
uses: actions/setup-java@v1.4.3
with:
- java-version: 17
+ java-version: 18
- name: Checkout repository
uses: actions/checkout@v2
diff --git a/pom.xml b/pom.xml
index ab3f5c3..d1a1fd3 100644
--- a/pom.xml
+++ b/pom.xml
@@ -5,7 +5,7 @@
com.erikmafo
littletableviewer
- 1.0.1
+ 1.0.2
jar
Little Table Viewer
@@ -39,7 +39,7 @@
maven-compiler-plugin
3.10.1
- 17
+ 18
@@ -196,13 +196,13 @@
org.openjfx
javafx-controls
- 17.0.2
+ 18.0.2
compile
org.openjfx
javafx-fxml
- 17.0.2
+ 18.0.2
compile
diff --git a/src/main/java/com/erikmafo/ltviewer/model/BigtableCell.java b/src/main/java/com/erikmafo/ltviewer/model/BigtableCell.java
index 0fce859..9e29d4c 100644
--- a/src/main/java/com/erikmafo/ltviewer/model/BigtableCell.java
+++ b/src/main/java/com/erikmafo/ltviewer/model/BigtableCell.java
@@ -5,6 +5,8 @@
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
+import java.util.Base64;
+
/**
* A simple representation of a bigtable row cell.
*/
@@ -70,6 +72,8 @@ public String getQualifier() {
*/
public String getValueAsString() { return bytes.toStringUtf8(); }
+ public String getValueAsStringBase64() { return Base64.getEncoder().encodeToString(bytes.toByteArray()); }
+
/**
* Gets the value of the cell as a byte array.
*
diff --git a/src/main/java/com/erikmafo/ltviewer/model/BigtableValueConverter.java b/src/main/java/com/erikmafo/ltviewer/model/BigtableValueConverter.java
index ca4b402..60b9b66 100644
--- a/src/main/java/com/erikmafo/ltviewer/model/BigtableValueConverter.java
+++ b/src/main/java/com/erikmafo/ltviewer/model/BigtableValueConverter.java
@@ -129,6 +129,8 @@ private BigtableValue convertUsingValueType(BigtableCell cell, @NotNull CellDefi
return toBigtableValue(cell.getValueAsString(), valueTypeUpper);
case ValueTypeConstants.PROTO:
return toBigtableValue(ProtoUtil.toJson(cell.getByteString(), cellDefinition.getProtoObjectDefinition()), valueTypeUpper);
+ case ValueTypeConstants.BYTE_STRING:
+ return toBigtableValue(cell.getValueAsStringBase64(), valueTypeUpper);
default:
return toBigtableValue(cell.getValueAsString(), ValueTypeConstants.STRING);
}
diff --git a/src/main/java/com/erikmafo/ltviewer/model/ByteStringConverterImpl.java b/src/main/java/com/erikmafo/ltviewer/model/ByteStringConverterImpl.java
index d13a379..30c17b9 100644
--- a/src/main/java/com/erikmafo/ltviewer/model/ByteStringConverterImpl.java
+++ b/src/main/java/com/erikmafo/ltviewer/model/ByteStringConverterImpl.java
@@ -52,6 +52,9 @@ public ByteString toByteString(Field field, Value value) {
case ValueTypeConstants.LONG:
byteString = ByteStringConverterUtil.toByteString(value.asLong());
break;
+ case ValueTypeConstants.BYTE_STRING:
+ byteString = ByteStringConverterUtil.toByteStringFromBase64(value.asString());
+ break;
default: throw new IllegalArgumentException(String.format("Value type %s is not supported", valueType.toUpperCase()));
}
diff --git a/src/main/java/com/erikmafo/ltviewer/model/CellDefinition.java b/src/main/java/com/erikmafo/ltviewer/model/CellDefinition.java
index 8ec3f3d..4057f6d 100644
--- a/src/main/java/com/erikmafo/ltviewer/model/CellDefinition.java
+++ b/src/main/java/com/erikmafo/ltviewer/model/CellDefinition.java
@@ -62,6 +62,14 @@ public void setQualifier(String qualifier) {
this.qualifier = qualifier;
}
+ public ProtoObjectDefinition getProtoObjectDefinition() {
+ return protoObjectDefinition;
+ }
+
+ public void setProtoObjectDefinition(ProtoObjectDefinition protoObjectDefinition) {
+ this.protoObjectDefinition = protoObjectDefinition;
+ }
+
@Override
public boolean equals(Object o) {
if (this == o) return true;
@@ -85,8 +93,4 @@ public String toString() {
", qualifier='" + qualifier + '\'' +
'}';
}
-
- public ProtoObjectDefinition getProtoObjectDefinition() {
- return protoObjectDefinition;
- }
}
diff --git a/src/main/java/com/erikmafo/ltviewer/model/ProtoObjectDefinition.java b/src/main/java/com/erikmafo/ltviewer/model/ProtoObjectDefinition.java
index fce833b..84c5845 100644
--- a/src/main/java/com/erikmafo/ltviewer/model/ProtoObjectDefinition.java
+++ b/src/main/java/com/erikmafo/ltviewer/model/ProtoObjectDefinition.java
@@ -4,9 +4,9 @@
import org.jetbrains.annotations.NotNull;
public class ProtoObjectDefinition {
- private final String descriptorSetFile;
- private final String protoFile;
- private final String messageType;
+ private String descriptorSetFile;
+ private String protoFile;
+ private String messageType;
public ProtoObjectDefinition(String descriptorSetFile, String protoFile, String messageType) {
Check.notNullOrEmpty(descriptorSetFile, "descriptorSetFile");
diff --git a/src/main/java/com/erikmafo/ltviewer/model/ValueTypeConstants.java b/src/main/java/com/erikmafo/ltviewer/model/ValueTypeConstants.java
index edabdc7..12d532f 100644
--- a/src/main/java/com/erikmafo/ltviewer/model/ValueTypeConstants.java
+++ b/src/main/java/com/erikmafo/ltviewer/model/ValueTypeConstants.java
@@ -17,4 +17,6 @@ public class ValueTypeConstants {
public static final String JSON = "JSON";
public static final String PROTO = "PROTO";
+
+ public static final String BYTE_STRING = "BYTESTRING";
}
diff --git a/src/main/java/com/erikmafo/ltviewer/services/internal/testdata/PersonOuterClass.java b/src/main/java/com/erikmafo/ltviewer/services/internal/testdata/PersonOuterClass.java
index 08cb4e2..cb193b8 100644
--- a/src/main/java/com/erikmafo/ltviewer/services/internal/testdata/PersonOuterClass.java
+++ b/src/main/java/com/erikmafo/ltviewer/services/internal/testdata/PersonOuterClass.java
@@ -46,6 +46,12 @@ public interface PersonOrBuilder extends
* @return The age.
*/
int getAge();
+
+ /**
+ * bytes bytes = 4;
+ * @return The bytes.
+ */
+ com.google.protobuf.ByteString getBytes();
}
/**
* Protobuf type {@code Person}
@@ -62,6 +68,7 @@ private Person(com.google.protobuf.GeneratedMessageV3.Builder> builder) {
private Person() {
name_ = "";
id_ = "";
+ bytes_ = com.google.protobuf.ByteString.EMPTY;
}
@java.lang.Override
@@ -111,6 +118,11 @@ private Person(
age_ = input.readInt32();
break;
}
+ case 34: {
+
+ bytes_ = input.readBytes();
+ break;
+ }
default: {
if (!parseUnknownField(
input, unknownFields, extensionRegistry, tag)) {
@@ -232,6 +244,17 @@ public int getAge() {
return age_;
}
+ public static final int BYTES_FIELD_NUMBER = 4;
+ private com.google.protobuf.ByteString bytes_;
+ /**
+ * bytes bytes = 4;
+ * @return The bytes.
+ */
+ @java.lang.Override
+ public com.google.protobuf.ByteString getBytes() {
+ return bytes_;
+ }
+
private byte memoizedIsInitialized = -1;
@java.lang.Override
public final boolean isInitialized() {
@@ -255,6 +278,9 @@ public void writeTo(com.google.protobuf.CodedOutputStream output)
if (age_ != 0) {
output.writeInt32(3, age_);
}
+ if (!bytes_.isEmpty()) {
+ output.writeBytes(4, bytes_);
+ }
unknownFields.writeTo(output);
}
@@ -274,6 +300,10 @@ public int getSerializedSize() {
size += com.google.protobuf.CodedOutputStream
.computeInt32Size(3, age_);
}
+ if (!bytes_.isEmpty()) {
+ size += com.google.protobuf.CodedOutputStream
+ .computeBytesSize(4, bytes_);
+ }
size += unknownFields.getSerializedSize();
memoizedSize = size;
return size;
@@ -295,6 +325,8 @@ public boolean equals(final java.lang.Object obj) {
.equals(other.getId())) return false;
if (getAge()
!= other.getAge()) return false;
+ if (!getBytes()
+ .equals(other.getBytes())) return false;
if (!unknownFields.equals(other.unknownFields)) return false;
return true;
}
@@ -312,6 +344,8 @@ public int hashCode() {
hash = (53 * hash) + getId().hashCode();
hash = (37 * hash) + AGE_FIELD_NUMBER;
hash = (53 * hash) + getAge();
+ hash = (37 * hash) + BYTES_FIELD_NUMBER;
+ hash = (53 * hash) + getBytes().hashCode();
hash = (29 * hash) + unknownFields.hashCode();
memoizedHashCode = hash;
return hash;
@@ -451,6 +485,8 @@ public Builder clear() {
age_ = 0;
+ bytes_ = com.google.protobuf.ByteString.EMPTY;
+
return this;
}
@@ -480,6 +516,7 @@ public PersonOuterClass.Person buildPartial() {
result.name_ = name_;
result.id_ = id_;
result.age_ = age_;
+ result.bytes_ = bytes_;
onBuilt();
return result;
}
@@ -539,6 +576,9 @@ public Builder mergeFrom(PersonOuterClass.Person other) {
if (other.getAge() != 0) {
setAge(other.getAge());
}
+ if (other.getBytes() != com.google.protobuf.ByteString.EMPTY) {
+ setBytes(other.getBytes());
+ }
this.mergeUnknownFields(other.unknownFields);
onChanged();
return this;
@@ -750,6 +790,40 @@ public Builder clearAge() {
onChanged();
return this;
}
+
+ private com.google.protobuf.ByteString bytes_ = com.google.protobuf.ByteString.EMPTY;
+ /**
+ * bytes bytes = 4;
+ * @return The bytes.
+ */
+ @java.lang.Override
+ public com.google.protobuf.ByteString getBytes() {
+ return bytes_;
+ }
+ /**
+ * bytes bytes = 4;
+ * @param value The bytes to set.
+ * @return This builder for chaining.
+ */
+ public Builder setBytes(com.google.protobuf.ByteString value) {
+ if (value == null) {
+ throw new NullPointerException();
+ }
+
+ bytes_ = value;
+ onChanged();
+ return this;
+ }
+ /**
+ * bytes bytes = 4;
+ * @return This builder for chaining.
+ */
+ public Builder clearBytes() {
+
+ bytes_ = getDefaultInstance().getBytes();
+ onChanged();
+ return this;
+ }
@java.lang.Override
public final Builder setUnknownFields(
final com.google.protobuf.UnknownFieldSet unknownFields) {
@@ -817,8 +891,9 @@ public PersonOuterClass.Person getDefaultInstanceForType() {
descriptor;
static {
java.lang.String[] descriptorData = {
- "\n\014person.proto\"/\n\006Person\022\014\n\004name\030\001 \001(\t\022\n" +
- "\n\002id\030\002 \001(\t\022\013\n\003age\030\003 \001(\005b\006proto3"
+ "\n\014person.proto\">\n\006Person\022\014\n\004name\030\001 \001(\t\022\n" +
+ "\n\002id\030\002 \001(\t\022\013\n\003age\030\003 \001(\005\022\r\n\005bytes\030\004 \001(\014b\006" +
+ "proto3"
};
descriptor = com.google.protobuf.Descriptors.FileDescriptor
.internalBuildGeneratedFileFrom(descriptorData,
@@ -829,7 +904,7 @@ public PersonOuterClass.Person getDefaultInstanceForType() {
internal_static_Person_fieldAccessorTable = new
com.google.protobuf.GeneratedMessageV3.FieldAccessorTable(
internal_static_Person_descriptor,
- new java.lang.String[] { "Name", "Id", "Age", });
+ new java.lang.String[] { "Name", "Id", "Age", "Bytes", });
}
// @@protoc_insertion_point(outer_class_scope)
diff --git a/src/main/java/com/erikmafo/ltviewer/services/internal/testdata/TestDataUtil.java b/src/main/java/com/erikmafo/ltviewer/services/internal/testdata/TestDataUtil.java
index 52d188b..54fc7e3 100644
--- a/src/main/java/com/erikmafo/ltviewer/services/internal/testdata/TestDataUtil.java
+++ b/src/main/java/com/erikmafo/ltviewer/services/internal/testdata/TestDataUtil.java
@@ -1,9 +1,7 @@
package com.erikmafo.ltviewer.services.internal.testdata;
import com.erikmafo.ltviewer.model.BigtableInstance;
-import com.erikmafo.ltviewer.model.ProtoObjectDefinition;
import com.erikmafo.ltviewer.services.internal.BigtableEmulatorSettingsProvider;
-import com.erikmafo.ltviewer.util.ProtoUtil;
import com.google.cloud.bigtable.admin.v2.BigtableTableAdminClient;
import com.google.cloud.bigtable.admin.v2.models.CreateTableRequest;
import com.google.cloud.bigtable.data.v2.BigtableDataClient;
@@ -11,7 +9,6 @@
import com.google.protobuf.ByteString;
import org.jetbrains.annotations.NotNull;
-import java.io.Console;
import java.io.IOException;
import static com.erikmafo.ltviewer.util.ByteStringConverterUtil.toByteString;
@@ -35,6 +32,7 @@ public class TestDataUtil {
private static final String PROJECT_0 = "project-0";
private static final String INSTANCE_0 = "instance-0";
private static final String TABLE_0 = "table-0";
+ public static final ByteString BYTE_STRING_TEST_VALUE = toByteString(842098349384L);
public static void injectWithTestData(BigtableEmulatorSettingsProvider settingsProvider) {
try {
@@ -74,7 +72,7 @@ private static void addData(String tableName, com.google.cloud.bigtable.data.v2.
.setCell("f1", toByteString("q3"), toByteString(i + 0.5))
.setCell("f1", toByteString("q4"), toByteString(JSON_TEST_DATA))
.setCell("f2", toByteString("q1"), toByteString("string-" + i))
- .setCell("f3", toByteString("q1"), toByteString("string-" + i))
+ .setCell("f3", toByteString("q1"), BYTE_STRING_TEST_VALUE)
.setCell("f4", toByteString("q1"), getPerson(i).toByteString());
dataClient.mutateRow(mutation);
}
@@ -87,6 +85,7 @@ private static PersonOuterClass.Person getPerson(int i) {
.setName("Person-" + i)
.setId("" + i)
.setAge(i % 100)
+ .setBytes(BYTE_STRING_TEST_VALUE)
.build();
}
}
diff --git a/src/main/java/com/erikmafo/ltviewer/services/internal/testdata/descriptorset.pb b/src/main/java/com/erikmafo/ltviewer/services/internal/testdata/descriptorset.pb
index 860357b..a96ea79 100644
--- a/src/main/java/com/erikmafo/ltviewer/services/internal/testdata/descriptorset.pb
+++ b/src/main/java/com/erikmafo/ltviewer/services/internal/testdata/descriptorset.pb
@@ -1,7 +1,8 @@
-V
-person.proto">
+l
+person.proto"T
Person
name ( Rname
id ( Rid
-age (Ragebproto3
\ No newline at end of file
+age (Rage
+bytes (Rbytesbproto3
\ No newline at end of file
diff --git a/src/main/java/com/erikmafo/ltviewer/services/internal/testdata/person.proto b/src/main/java/com/erikmafo/ltviewer/services/internal/testdata/person.proto
index 170a338..f04e8d5 100644
--- a/src/main/java/com/erikmafo/ltviewer/services/internal/testdata/person.proto
+++ b/src/main/java/com/erikmafo/ltviewer/services/internal/testdata/person.proto
@@ -4,4 +4,5 @@ message Person {
string name = 1;
string id = 2;
int32 age = 3;
+ bytes bytes = 4;
}
\ No newline at end of file
diff --git a/src/main/java/com/erikmafo/ltviewer/ui/dialogs/DialogLoaderUtil.java b/src/main/java/com/erikmafo/ltviewer/ui/dialogs/DialogLoaderUtil.java
index f69f770..8328ee0 100644
--- a/src/main/java/com/erikmafo/ltviewer/ui/dialogs/DialogLoaderUtil.java
+++ b/src/main/java/com/erikmafo/ltviewer/ui/dialogs/DialogLoaderUtil.java
@@ -14,22 +14,20 @@ public class DialogLoaderUtil {
@NotNull
public static CompletableFuture displayDialogAndAwaitResult(T initialValue, String fxmlFile) {
- CompletableFuture result = new CompletableFuture<>();
- Dialog dialog = new Dialog<>();
- var protoObjectDialogLoader = getLoader(fxmlFile);
- DialogPane protoObjectDialog = null;
- try {
- protoObjectDialog = protoObjectDialogLoader.load();
- } catch (IOException e) {
- throw new RuntimeException(e);
- }
- DialogController controller = protoObjectDialogLoader.getController();
+ CompletableFuture completableFuture = new CompletableFuture<>();
+ var fxmlLoader = getLoader(fxmlFile);
+ DialogPane dialogPane = getDialogPane(fxmlLoader);
+ DialogController controller = getDialogController(initialValue, fxmlLoader);
+ var dialog = createDialog(completableFuture, dialogPane, controller);
+ dialog.show();
- if (initialValue != null) {
- controller.setResult(initialValue);
- }
+ return completableFuture;
+ }
- dialog.setDialogPane(protoObjectDialog);
+ @NotNull
+ private static Dialog createDialog(CompletableFuture completableFuture, DialogPane dialogPane, DialogController controller) {
+ Dialog dialog = new Dialog<>();
+ dialog.setDialogPane(dialogPane);
dialog.setResultConverter(param -> {
if (ButtonBar.ButtonData.OK_DONE.equals(param.getButtonData())) {
return controller.getResult();
@@ -37,14 +35,31 @@ public static CompletableFuture displayDialogAndAwaitResult(T initialValu
return null;
});
dialog.setOnHidden(ignore -> {
- var resultValue = dialog.getResult();
- if (controller.validateResult(resultValue)) {
- result.complete(resultValue);
+ var resultValue = controller.getResult();
+ if (resultValue == null || controller.validateResult(resultValue)) {
+ completableFuture.complete(resultValue);
}
});
- dialog.show();
+ return dialog;
+ }
+
+ private static DialogController getDialogController(T initialValue, @NotNull FXMLLoader fxmlLoader) {
+ DialogController controller = fxmlLoader.getController();
+
+ if (initialValue != null) {
+ controller.setResult(initialValue);
+ }
+ return controller;
+ }
- return result;
+ private static DialogPane getDialogPane(@NotNull FXMLLoader fxmlLoader) {
+ DialogPane dialogPane = null;
+ try {
+ dialogPane = fxmlLoader.load();
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ return dialogPane;
}
@NotNull
diff --git a/src/main/java/com/erikmafo/ltviewer/ui/dialogs/TableSettingsDialog.java b/src/main/java/com/erikmafo/ltviewer/ui/dialogs/TableSettingsDialog.java
index 23385d8..3401379 100644
--- a/src/main/java/com/erikmafo/ltviewer/ui/dialogs/TableSettingsDialog.java
+++ b/src/main/java/com/erikmafo/ltviewer/ui/dialogs/TableSettingsDialog.java
@@ -157,7 +157,7 @@ private void addSchemaRow(@NotNull BigtableColumn column, @Nullable String value
HBox hbox = new HBox();
ChoiceBox choiceBox = new ChoiceBox<>();
choiceBox.setValue(valueType != null ? valueType : "String");
- choiceBox.getItems().setAll(Arrays.asList("String", "Double", "Float", "Integer", "Long", "Short", "Json", "Proto"));
+ choiceBox.getItems().setAll(Arrays.asList("String", "Double", "Float", "Integer", "Long", "Short", "Json", "Proto", "ByteString"));
choiceBox.setPrefWidth(CHOICE_BOX_PREF_WIDTH);
GlyphFont fontAwesome = GlyphFontRegistry.font("FontAwesome");
Button configureProtoObjectButton = new Button("", fontAwesome.create(FontAwesome.Glyph.COG));
diff --git a/src/main/java/com/erikmafo/ltviewer/ui/queryresult/cell/CellView.java b/src/main/java/com/erikmafo/ltviewer/ui/queryresult/cell/CellView.java
index 32b9541..c9e996f 100644
--- a/src/main/java/com/erikmafo/ltviewer/ui/queryresult/cell/CellView.java
+++ b/src/main/java/com/erikmafo/ltviewer/ui/queryresult/cell/CellView.java
@@ -11,7 +11,6 @@
import javafx.fxml.FXML;
import javafx.scene.Node;
import javafx.scene.control.Label;
-import javafx.scene.control.TreeView;
import javafx.scene.layout.*;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
diff --git a/src/main/java/com/erikmafo/ltviewer/util/ByteStringConverterUtil.java b/src/main/java/com/erikmafo/ltviewer/util/ByteStringConverterUtil.java
index f6fc061..5017de0 100644
--- a/src/main/java/com/erikmafo/ltviewer/util/ByteStringConverterUtil.java
+++ b/src/main/java/com/erikmafo/ltviewer/util/ByteStringConverterUtil.java
@@ -6,6 +6,7 @@
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
+import java.util.Base64;
public class ByteStringConverterUtil {
@@ -15,6 +16,12 @@ public static ByteString toByteString(String stringUtf8) {
return ByteString.copyFromUtf8(stringUtf8);
}
+ @NotNull
+ @Contract("_ -> new")
+ public static ByteString toByteStringFromBase64(String stringBase64) {
+ return ByteString.copyFrom(Base64.getDecoder().decode(stringBase64));
+ }
+
@NotNull
public static ByteString toByteString(long value) {
var buffer = ByteBuffer