Segmented.java
package com.maybeitssquid.sensitive;
import java.util.Arrays;
/**
* A {@link Sensitive} value that backed by multiple segments of the same type.
*
* @param <T> the type of the individual segments. This type should have well-defined {@link
* Object#equals(Object)} and {@link Object#hashCode()} methods so that the corresponding
* methods on this class meets the contract.
*/
public class Segmented<T> extends Sensitive<T[]> {
/**
* Creates a new Segmented container with the specified array. The array is cloned to prevent
* external mutation.
*
* @param value the array of sensitive values; must not be {@code null}
* @throws NullPointerException if value is {@code null}
*/
public Segmented(final T[] value) {
super(value.clone());
}
/**
* Returns a clone of the contained array to prevent external mutation. This override provides
* additional protection for array-backed sensitive data.
*
* @return a clone of the contained array, or {@code null} if the contained value is null
*/
@Override
protected final T[] getValue() {
final T[] value = this.supplier.get();
return value == null ? null : value.clone();
}
/**
* Returns the value of the contained array at the specified index. Equivalent to {@code
* getValue()[index]}, adding null and bounds checking and avoiding the clone.
*
* @param index the index into the contained array.
* @return the value of the contained array at the specified index, or {@code null} if the
* contained value is null or the index is out of range.
*/
protected final T getValue(final int index) {
final T[] value = this.supplier.get();
return value == null || index < 0 || index >= value.length ? null : value[index];
}
/**
* Returns the hash of the enclosed {@code raw} data as generated by invoking {@link
* Arrays#hashCode(Object[])} on the contained raw data.
*
* @return {@inheritDoc}
*/
@Override
public int hashCode() {
return Arrays.hashCode(this.supplier.get());
}
/**
* Returns true if the types match and the enclosed raw data are equal as indicated by invoking
* {@link Arrays#equals(Object[], Object[])}.
*
* @param o {@inheritDoc}
* @return {@inheritDoc}
*/
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Segmented<?> other = (Segmented<?>) o;
return Arrays.equals(this.supplier.get(), other.supplier.get());
}
}