JavaFX table view don't display scrambled strings

398 views Asked by At

My problem is that my JavaFX TableView cannot display my String that is crypted with SHA-256. It works with a normal string. Here my code for the my scramble method.

private String scrambleName(String name, String surname)
{
MessageDigest messageDigest;
String cryptedName;

StringBuilder builder = new StringBuilder();
builder.append(name);
builder.append(" ");
builder.append(surname);

String fullName = builder.toString();

try
{
    messageDigest = MessageDigest.getInstance("SHA-256");
    messageDigest.update(fullName.getBytes());
    cryptedName = new String(messageDigest.digest());
    return cryptedName;
} catch (NoSuchAlgorithmException ex)
{
    Logger.getLogger(Scrambler.class.getName()).log(Level.SEVERE, null, ex);
}
return null;
}

This method returns a string for my scrambled vote object.

public class ScrambledVote
{
private int key;
private String scrambledName;
private int age;
private String party;

public ScrambledVote(int key, String scrambledName, int age, String party)
{
this.key = key;
this.scrambledName = scrambledName;
this.age = age;
this.party = party;
}
//Getter Setter

I load the data from a file. The command line output works fine. But the TableView throws an exception.

Exception in thread "JavaFX Application Thread" java.lang.ArrayIndexOutOfBoundsException: 0
at com.sun.javafx.font.directwrite.DWGlyphLayout.getIndices(DWGlyphLayout.java:198)
at com.sun.javafx.font.directwrite.DWGlyphLayout.renderShape(DWGlyphLayout.java:401)
at com.sun.javafx.font.directwrite.DWGlyphLayout.layout(DWGlyphLayout.java:154)
at com.sun.javafx.text.PrismTextLayout.shape(PrismTextLayout.java:832)
at com.sun.javafx.text.PrismTextLayout.layout(PrismTextLayout.java:1062)
at com.sun.javafx.text.PrismTextLayout.ensureLayout(PrismTextLayout.java:221)
at com.sun.javafx.text.PrismTextLayout.getBounds(PrismTextLayout.java:244)
at com.sun.javafx.scene.control.skin.Utils.computeTextHeight(Utils.java:129)
at com.sun.javafx.scene.control.skin.LabeledSkinBase.computePrefHeight(LabeledSkinBase.java:832)
at javafx.scene.control.Control.computePrefHeight(Control.java:543)
at javafx.scene.Parent.prefHeight(Parent.java:918)
at javafx.scene.layout.Region.prefHeight(Region.java:1438)
at com.sun.javafx.scene.control.skin.TableRowSkinBase.computePrefHeight(TableRowSkinBase.java:544)
at javafx.scene.control.Control.computePrefHeight(Control.java:543)
at javafx.scene.Parent.prefHeight(Parent.java:924)
at javafx.scene.layout.Region.prefHeight(Region.java:1438)
at com.sun.javafx.scene.control.skin.VirtualFlow.resizeCellSize(VirtualFlow.java:1782)
at com.sun.javafx.scene.control.skin.VirtualFlow.addTrailingCells(VirtualFlow.java:1212)
at com.sun.javafx.scene.control.skin.VirtualFlow.layoutChildren(VirtualFlow.java:1102)
at javafx.scene.Parent.layout(Parent.java:1076)
at javafx.scene.Parent.layout(Parent.java:1082)
at javafx.scene.Parent.layout(Parent.java:1082)
at javafx.scene.Scene.doLayoutPass(Scene.java:576)
at javafx.scene.Scene$ScenePulseListener.pulse(Scene.java:2386)
at com.sun.javafx.tk.Toolkit$3.run(Toolkit.java:321)
at com.sun.javafx.tk.Toolkit$3.run(Toolkit.java:319)
at java.security.AccessController.doPrivileged(Native Method)
at com.sun.javafx.tk.Toolkit.runPulse(Toolkit.java:319)
at com.sun.javafx.tk.Toolkit.firePulse(Toolkit.java:348)
at com.sun.javafx.tk.quantum.QuantumToolkit.pulse(QuantumToolkit.java:479)
at com.sun.javafx.tk.quantum.QuantumToolkit.pulse(QuantumToolkit.java:460)
at com.sun.javafx.tk.quantum.QuantumToolkit$13.run(QuantumToolkit.java:327)
at com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:95)
at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
at com.sun.glass.ui.win.WinApplication.access$300(WinApplication.java:39)
at com.sun.glass.ui.win.WinApplication$4$1.run(WinApplication.java:112)
at java.lang.Thread.run(Thread.java:745)

How can my TableView display this kind of scrambled String?

@FXML
protected void loadFile()
{
allScrambledVotes.clear();
HashTable hashTable = new HashTable(txtPath.getText());
LinkList[] allVotes = hashTable.getArray();
Scrambler scrambler = new Scrambler();
int k = 0;
for (LinkList vote : allVotes)
{
    for (int j = 0; j < vote.getSize(); j++)
    {
    Vote v = vote.findVote(j);
    scrambler.put(k, v);
    allScrambledVotes.add(scrambler.get(k));
    System.out.println(allScrambledVotes.get(k));
    k++;
    }
}
table.setItems(allScrambledVotes);
System.out.println("Hello World");
} 

I forget my loadFile method. I load the data from a hashtable with my own functions. The error occurs after the Hello World sysout.

1

There are 1 answers

3
James_D On BEST ANSWER

The digest() method returns an array of bytes: these are not the ascii values of the string representation of the digest. You're getting the error (I think) because JavaFX is unable to render a character for some of the byte values you have.

Instead of

cryptedName = new String(messageDigest.digest());
return cryptedName;

try something along the lines of

StringBuilder cryptedName = new StringBuilder();
for (byte b : messageDigest.digest()) {
    cryptedName.append(String.format("%02x", b));
}
return cryptedName.toString();

Here is a complete example:

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

import javafx.application.Application;
import javafx.beans.binding.StringBinding;
import javafx.beans.property.ReadOnlyStringWrapper;
import javafx.beans.property.SimpleStringProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.geometry.Insets;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.layout.VBox;
import javafx.scene.text.Font;
import javafx.stage.Stage;
;

public class TableViewSample extends Application {

    private final TableView<Person> table = new TableView<>();
    private final ObservableList<Person> data =
        FXCollections.observableArrayList(
            new Person("Jacob", "Smith", "[email protected]"),
            new Person("Isabella", "Johnson", "[email protected]"),
            new Person("Ethan", "Williams", "[email protected]"),
            new Person("Emma", "Jones", "[email protected]"),
            new Person("Michael", "Brown", "[email protected]")
        );

    public static void main(String[] args) {
        launch(args);
    }

    @Override
    public void start(Stage stage) {
        Scene scene = new Scene(new Group());
        stage.setTitle("Table View Sample");
        stage.setWidth(450);
        stage.setHeight(500);

        final Label label = new Label("Address Book");
        label.setFont(new Font("Arial", 20));

        table.setEditable(true);


        TableColumn<Person, String> firstNameCol = new TableColumn<>("First Name");
        firstNameCol.setMinWidth(100);
        firstNameCol.setCellValueFactory(
                new PropertyValueFactory<>("firstName"));

        TableColumn<Person, String> lastNameCol = new TableColumn<>("Last Name");
        lastNameCol.setMinWidth(100);
        lastNameCol.setCellValueFactory(
                new PropertyValueFactory<>("lastName"));

        TableColumn<Person, String> emailCol = new TableColumn<>("Email");
        emailCol.setMinWidth(200);
        emailCol.setCellValueFactory(
                new PropertyValueFactory<>("email"));

        TableColumn<Person, String> digestCol = new TableColumn<>("Digest");
        digestCol.setMinWidth(200);
        digestCol.setCellValueFactory(
                new PropertyValueFactory<>("digestedName"));

        table.setItems(data);
        table.getColumns().addAll(firstNameCol, lastNameCol, emailCol, digestCol);

        final VBox vbox = new VBox();
        vbox.setSpacing(5);
        vbox.setPadding(new Insets(10, 0, 0, 10));
        vbox.getChildren().addAll(label, table);

        ((Group) scene.getRoot()).getChildren().addAll(vbox);

        stage.setScene(scene);
        stage.show();
    }

    public static class Person {

        private final SimpleStringProperty firstName;
        private final SimpleStringProperty lastName;
        private final SimpleStringProperty email;

        private final MessageDigest digest ;    

        private final ReadOnlyStringWrapper digestedName ;

        private Person(String fName, String lName, String email) {
            this.firstName = new SimpleStringProperty(fName);
            this.lastName = new SimpleStringProperty(lName);
            this.email = new SimpleStringProperty(email);
            try {
                digest = MessageDigest.getInstance("SHA-256");
            } catch (NoSuchAlgorithmException e) {
                throw new Error(e);
            }

            this.digestedName = new ReadOnlyStringWrapper();
            digestedName.bind(new StringBinding() {
                {
                    bind(firstName, lastName);
                }
                @Override
                public String computeValue() {
                    String fullName = getFirstName() + " " + getLastName();
                    return scrambleName(fullName);
                }
            });
        }

        private String scrambleName(String fullName) {
            digest.update(fullName.getBytes());
            StringBuilder result = new StringBuilder();
            for (byte b : digest.digest()) {
                result.append(String.format("%02x", b));
            }
            return result.toString();
        }

        public String getFirstName() {
            return firstName.get();
        }

        public void setFirstName(String fName) {
            firstName.set(fName);
        }

        public String getLastName() {
            return lastName.get();
        }

        public void setLastName(String fName) {
            lastName.set(fName);
        }

        public String getEmail() {
            return email.get();
        }

        public void setEmail(String fName) {
            email.set(fName);
        }

        public String getDigestedName() {
            return digestedName.get();
        }
    }
}