001package io.jstach.jstachio.context; 002 003import java.io.IOException; 004 005import io.jstach.jstache.JStacheConfig; 006import io.jstach.jstachio.JStachio; 007import io.jstach.jstachio.Output; 008import io.jstach.jstachio.Output.EncodedOutput; 009import io.jstach.jstachio.Template; 010 011/** 012 * A special JStachio that can render models with a loose typed context object bound to 013 * {@value ContextNode#CONTEXT_BINDING_NAME}. 014 * 015 * @see JStachio 016 * @see ContextNode 017 * @since 1.3.0 018 * @author agentgt 019 */ 020public interface ContextJStachio extends JStachio { 021 022 /** 023 * Renders the passed in model <strong>with a context</strong>. 024 * @param <A> output type 025 * @param <E> error type 026 * @param model a model assumed never to be <code>null</code>. 027 * @param context context node bound to {@value ContextNode#CONTEXT_BINDING_NAME}. 028 * @param appendable the output to write to. 029 * @return the output passed in returned for convenience. 030 * @throws E if there is an error writing to the output 031 */ 032 public <A extends Output<E>, E extends Exception> A execute(Object model, // 033 ContextNode context, // 034 A appendable) throws E; 035 036 /** 037 * Renders the passed in model <strong>with a context</strong> directly to a binary 038 * stream leveraging pre-encoded parts of the template. This <em>may</em> improve 039 * performance when rendering UTF-8 to an OutputStream as some of the encoding is done 040 * in advance. Because the encoding is done statically you cannot pass the charset in. 041 * The chosen charset comes from {@link JStacheConfig#charset()}. 042 * @param <A> output type 043 * @param <E> error type 044 * @param model a model assumed never to be <code>null</code>. 045 * @param context context node bound to {@value ContextNode#CONTEXT_BINDING_NAME}. 046 * @param output to write to. 047 * @return the passed in output for convenience 048 * @throws E if an error occurs while writing to output 049 */ 050 <A extends io.jstach.jstachio.Output.EncodedOutput<E>, E extends Exception> A write( // 051 Object model, // 052 ContextNode context, // 053 A output) throws E; 054 055 /** 056 * Decorates a JStachio instance as a {@link ContextJStachio} if it is not already 057 * one. 058 * @param jstachio the instance to be wrapped. 059 * @return the passed in jstachio if it is already a {@link ContextJStachio} otherwise 060 * wraps the passed in instance. 061 */ 062 public static ContextJStachio of(JStachio jstachio) { 063 if (jstachio instanceof ContextJStachio cj) { 064 return cj; 065 } 066 return new ForwardingJStachio(jstachio); 067 } 068 069} 070 071record ForwardingJStachio(JStachio delegate) implements ContextJStachio { 072 073 @Override 074 public <A extends Output<E>, E extends Exception> A execute(Object model, A appendable) throws E { 075 return delegate.execute(model, appendable); 076 } 077 078 @Override 079 public <A extends EncodedOutput<E>, E extends Exception> A write(Object model, A output) throws E { 080 return delegate.write(model, output); 081 } 082 083 @Override 084 public Template<Object> findTemplate(Object model) throws Exception { 085 return delegate.findTemplate(model); 086 } 087 088 @Override 089 public boolean supportsType(Class<?> modelType) { 090 return delegate.supportsType(modelType); 091 } 092 093 @Override 094 public void execute(Object model, Appendable appendable) throws IOException { 095 delegate.execute(model, appendable); 096 } 097 098 @Override 099 public StringBuilder execute(Object model, StringBuilder sb) { 100 return delegate.execute(model, sb); 101 } 102 103 @Override 104 public String execute(Object model) { 105 return delegate.execute(model); 106 } 107 108 @Override 109 public <A extends Output<E>, E extends Exception> A execute(Object model, ContextNode context, A appendable) 110 throws E { 111 var out = ContextAwareOutput.of(appendable, context); 112 return delegate.execute(model, out).getOutput(); 113 } 114 115 @Override 116 public <A extends EncodedOutput<E>, E extends Exception> A write(Object model, ContextNode context, A output) 117 throws E { 118 var out = ContextAwareOutput.of(output, context); 119 return delegate.write(model, out).getOutput(); 120 } 121 122}