Renderer.java
package com.maybeitssquid.sensitive;
/**
* Renders sensitive data as a {@link CharSequence} with appropriate redaction. Implementations
* control how much information is revealed based on formatting parameters.
*
* <h2>Precision Semantics</h2>
*
* The precision parameter controls how much unredacted data to show:
*
* <ul>
* <li>{@code precision = -1}: Default behavior (typically shows half the data,
* implementation-dependent)
* <li>{@code precision >= 0}: Number of unredacted segments/characters to show (e.g., for SSN
* "123-45-6789", precision=4 shows last 4 digits: "***-**-6789")
* </ul>
*
* Note: Higher precision values show MORE data, not less. Precision=0 typically shows no data.
*
* <h2>Usage</h2>
*
* Renderers are typically used by subclasses of {@link Sensitive} that override {@link
* Sensitive#getRenderer()} to provide a shared renderer instance:
*
* <pre>{@code
* public class SecretCode extends Sensitive<String> {
* private static final Renderer<String> RENDERER = (value, precision) -> {
* return "***";
* };
*
* public SecretCode(String value) {
* super(value);
* }
*
* @Override
* protected Renderer<String> getRenderer() {
* return RENDERER;
* }
* }
* }</pre>
*
* @param <T> the type of data to render
* @see Sensitive
* @see Sensitive#getRenderer()
* @see java.util.Formattable
*/
@FunctionalInterface
public interface Renderer<T> {
/**
* Renders data with the appropriate redaction.
*
* @param t the data to render
* @param precision the number of unredacted segments to show (or -1 for default)
* @return the rendered (possibly redacted) representation
*/
CharSequence apply(T t, int precision);
/** Singleton empty renderer — non-capturing, so one instance suffices for all type parameters. */
@SuppressWarnings("rawtypes")
Renderer EMPTY = (t, p) -> "";
/**
* Returns a renderer that always returns an empty string, ensuring no sensitive data is
* disclosed.
*
* <p>This is the default renderer used by {@link Sensitive#getRenderer()} and provides maximum
* protection by revealing nothing about the contained value.
*
* @param <T> the type of data the renderer accepts (ignored since output is always empty)
* @return a renderer that always returns an empty string
*/
@SuppressWarnings("unchecked")
static <T> Renderer<T> empty() {
return EMPTY;
}
}