ReportRenderContext.java
package com.taxonomy.extension.api.report;
import com.taxonomy.dto.ArchitectureReport;
import java.io.Serial;
import java.io.Serializable;
import java.util.Map;
import java.util.Objects;
/**
* Immutable input for a report renderer extension.
*
* <p>The original architecture-report accessor is retained for source compatibility.
* New report families use {@link #ofPayload(Object)} and obtain their typed model with
* {@link #payloadAs(Class)}. This keeps the extension API framework-free while allowing
* more than one report family to share the same renderer registry.</p>
*/
@SuppressWarnings("serial")
public final class ReportRenderContext implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
private final Object payload;
private final Map<String, Object> options;
/**
* Source-compatible constructor retained from the original record API.
*/
public ReportRenderContext(
ArchitectureReport report,
Map<String, Object> options) {
this((Object) report, options);
}
private ReportRenderContext(
Object payload,
Map<String, Object> options) {
this.payload = Objects.requireNonNull(payload, "report payload must not be null");
this.options = options == null ? Map.of() : Map.copyOf(options);
}
/**
* Backward-compatible accessor for the built-in architecture report family.
*/
public ArchitectureReport report() {
return payloadAs(ArchitectureReport.class);
}
/** Returns the untyped report payload for generic infrastructure. */
public Object payload() {
return payload;
}
/** Returns the immutable renderer options. */
public Map<String, Object> options() {
return options;
}
/**
* Requires the payload to have the expected report-model type.
*
* @throws IllegalArgumentException when a renderer is invoked with the wrong model
*/
public <T> T payloadAs(Class<T> expectedType) {
Objects.requireNonNull(expectedType, "expectedType must not be null");
if (!expectedType.isInstance(payload)) {
throw new IllegalArgumentException(
"Report renderer expected " + expectedType.getName()
+ " but received " + payload.getClass().getName());
}
return expectedType.cast(payload);
}
@Override
public boolean equals(Object other) {
return this == other
|| other instanceof ReportRenderContext context
&& payload.equals(context.payload)
&& options.equals(context.options);
}
@Override
public int hashCode() {
return Objects.hash(payload, options);
}
@Override
public String toString() {
return "ReportRenderContext[payload=" + payload + ", options=" + options + "]";
}
/** Creates a context for the original architecture-report family. */
public static ReportRenderContext of(ArchitectureReport report) {
return new ReportRenderContext(report, Map.of());
}
/** Creates a context for any registered report family. */
public static ReportRenderContext ofPayload(Object payload) {
return new ReportRenderContext(payload, Map.of());
}
/** Creates a context for any report family with renderer-specific options. */
public static ReportRenderContext ofPayload(
Object payload,
Map<String, Object> options) {
return new ReportRenderContext(payload, options);
}
}