1

I'm writing a JavaFX program, which should have user management and DB back-end. My data-model classes all use JavaFX-style properties (for easier UI integration, see e.g. this ).

But now I have come upon a technical problem my User class needs to have byte[] fields - namely these for password hash and salt.

Since MessageDigest and similar Java services expect byte[], the obvious solution of using ObjectProperty<Byte[]> becomes cumbersome, as with every usage of the fields I will have to create a new byte[] and copy the values.
For example:

SimpleObjectProperty<Byte[]> toHash = new SimpleObjectProperty<>();
MessageDigest md;
// initialize message digest and Byte[] property here...

// Does not compile - can't convert Byte[] to byte[]
// md.update(toHash.get());

// What does work: 
byte[] bytes = new byte[toHash.get().length];
for (int i=0; i<bytes.length; i++) 
    bytes[i] = toHash.get()[i];

md.update(bytes);

So my question is - is there a simple solution that will allow me to have JavaFX-style properties which I can get and set with primitive arrays?
Is implementing something like PrimitiveByteArrayProperty a sound choice, or even a feasible one? Do such solutions exist already?

Edit: I have apparently ignored the trivial solution of using ObjectProperty<byte[]>, having thought Java disallows generics of primitive arrays.

Community
  • 1
  • 1
Itai
  • 6,641
  • 6
  • 27
  • 51
  • Why do you need properties for password hash and salt? This should be determined deep in the database or LDAP layer, not a configurable property of the application. – user207421 Jun 19 '16 at 09:51
  • I'm not familiar with JavaFX, but I don't really understand what is cumbersome about using byte arrays, and why you need to create a new byte[] and copy values. I also don't get why you would use ObjectProperty and not ObjectProperty. Could you elaborate, and provide an example of cumbersome code? – JB Nizet Jun 19 '16 at 10:07
  • @JBNizet - I have assumed Java's restriction on primitives in type parameters extended to arrays. It appears I was wrong, in which case the question is indeed invalid. – Itai Jun 19 '16 at 10:11
  • @EJP - it is a part of a system for which the client requires custom user authorization handling. While technically these properties are never part of the UI I still have to implement them myself as per the specifications I was given. Seeing as all the rest of the handling is done with JFX properties, it is compelling not to break this "convention". – Itai Jun 19 '16 at 10:13

1 Answers1

0

The propper way to do that would be:

/**
 * The password hash.
 */
private final ObjectProperty<byte[]> toHash = new SimpleObjectProperty<>(this, "toHash");
/**
 * Setter for toHash property value.
 * @param value of the password hash.
 */
public void setToHash(byte[] value){
    toHash.set(value);
}
/**
 * Getter for toHash property value.
 * @return value of the password hash.
 */
public byte[] getToHash(){
    return toHash.get();
}
/**
 * Accessor to the javaFX property toHash.
 * @return toHash javaFX property.
 */
public ObjectPropery<byte[]> toHashProperty(){
    return toHash;
}

Tha javaFX convention is not to return the property specialization (ie: won't return SimpleObjectProperty), you should return the ObjectProperty, StringProperty, BooleanProperty... By the other hand, toHash sounds me like a function name that computes the hash, not a property itself. A better name may be passwordHash. Or if you hold the password plain text (obviously shouldn't do for security reasons) in another property, a propper javaFX way to do it should be:

//The password hash property.
private final ReadOnlyObjectWrapper<byte[]> passwordHash =
new ReadOnlyObjectWrapper<>(this, "passwordHash");

//The password plain text property.
private final StringProperty passwordPlain =
new SimpleStringProperty(this, "passwordPlain");

public byte[] getPasswordHash(){
    return passwordHash.get();
}

public ReadOnlyObjectProperty<byte[]> passwordHashProperty(){
    return passwordHash.getReadOnlyProperty();
}

public MyClass(){
    //Bind your read only property to automatically reflect the plain password changes.
    passwordHash.bind(Bindings.createObjectBinding(this::computeHash, passwordPlain));
}

//Invoked from lambda method reference in object binding.
private byte[] computeHash(){
    //Here do your stuff to parse the password plain to byte[]
    return byteArray;
}
Dharman
  • 30,962
  • 25
  • 85
  • 135
bichoFlyer
  • 178
  • 9