javagenericsencryptionstacktink

java: incompatible types: T cannot be converted to java.lang.String


I am currently working on a encryption and decryption service for my application, using Google Tink.
The problem is the following: I want to program it without using (nearly) duplicate code and therefore I had the idea of using generics.
If parsing the Strings to a byte[] is the only option I will be doing that, but I'd rather not.
These are the methods & variables:


The 3 Stacks I am using:

private Stack<String> plaintextAccInformation = new Stack<>();
private Stack<byte[]> encryptedAccInformation = new Stack<>();
private Stack<String> decryptedAccInformation = new Stack<>();

The method, used to get the information from the Stack (which I wanted to solve with generics and also is not working). No. Parsing does not work, as the method has to be accessible with two different datatypes.
private <T> Account getInformation(Stack<T> stack) {
    boolean isApproved = stack.peek();
    stack.pop();
    boolean isAdmin = stack.peek();
    stack.pop();
    double balance = stack.peek();
    stack.pop();
    String password = stack.peek();
    stack.pop();
    String iBan = stack.peek();
    stack.pop();
    String uuid = stack.peek();
    stack.pop();

    return new Account(uuid, iBan, password, balance, isAdmin, isApproved);
}

The method used to encrypt all the data of an Account object.
The idea is to iterate through the ```Stack plaintextAccInformation``` and encrypt every variable in the Account object and then save each encrypted variable to a new ```Stack encryptedAccInformation```
public Account encrypt(Account account) throws GeneralSecurityException {
        this.plaintextAccInformation.empty();
        this.encryptedAccInformation.empty();

        agjEncryption = new AesGcmJce(key.getBytes());

        this.plaintextAccInformation.push(account.getUuid());
        this.plaintextAccInformation.push(account.getIban());
        this.plaintextAccInformation.push(account.getPassword());
        this.plaintextAccInformation.push(String.valueOf(account.getBalance()));
        this.plaintextAccInformation.push(String.valueOf(account.isAdmin()));
        this.plaintextAccInformation.push(String.valueOf(account.isApproved()));

        Iterator<String> iterator = plaintextAccInformation.iterator();
        while (iterator.hasNext()) {
            encryptedAccInformation.push(agjEncryption.encrypt(plaintextAccInformation.peek().getBytes(), aad.getBytes()));
            plaintextAccInformation.pop();
        }

        return getInformation(this.encryptedAccInformation);
    }

The method used to decrypt the variables saved in the ```Stack encryptedAccInformation``` and save it to the ```Stack decryptedAccInformation```
    public Account decrypt() throws GeneralSecurityException {
        this.decryptedAccInformation.empty();

        this.agjDecryption = new AesGcmJce(key.getBytes());

        Iterator<byte[]> iterator2 = encryptedAccInformation.iterator();
        while (iterator2.hasNext()) {
            decryptedAccInformation.push(new String(agjDecryption.decrypt(encryptedAccInformation.peek(), aad.getBytes())));
            encryptedAccInformation.pop();
        }

        return getInformation(this.decryptedAccInformation);
    }

Solution

  • Assuming you're sure the stack will always be in the order you expect here (which you seem to be).

    Instead of a generic stack (which I believe limits you to only one value of T), you could use a stack of Object and cast the results of the peek() function.

    private Account getInformation(Stack<Object> stack) {
            Boolean isApproved = (Boolean) stack.peek();
            stack.pop();
            Boolean isAdmin = (Boolean) stack.peek();
            stack.pop();
            Double balance = (Double) stack.peek();
            stack.pop();
            String password = (String) stack.peek();
            stack.pop();
            String iBan = (String) stack.peek();
            stack.pop();
            String uuid = (String) stack.peek();
            stack.pop();
    
            return new Account(uuid, iBan, password, balance, isAdmin, isApproved);
    }