001package io.jstach.opt.spring.web;
002
003import java.io.BufferedWriter;
004import java.io.IOException;
005import java.io.OutputStreamWriter;
006import java.io.Writer;
007import java.nio.charset.Charset;
008import java.nio.charset.StandardCharsets;
009
010import org.springframework.http.HttpInputMessage;
011import org.springframework.http.HttpOutputMessage;
012import org.springframework.http.MediaType;
013import org.springframework.http.converter.AbstractHttpMessageConverter;
014import org.springframework.http.converter.HttpMessageNotReadableException;
015import org.springframework.http.converter.HttpMessageNotWritableException;
016import org.springframework.web.bind.annotation.ResponseBody;
017
018import io.jstach.jstachio.JStachio;
019
020/**
021 * Typesafe way to use JStachio in Spring Web.
022 * <p>
023 * For this to work the controllers need to return JStache models and have the controller
024 * method return annotated with {@link ResponseBody}.
025 * <p>
026 * <strong>Example:</strong> <pre><code class="language-java">
027 * &#64;JStache
028 * public record HelloModel(String message){}
029 *
030 * &#64;GetMapping(value = "/")
031 * &#64;ResponseBody
032 * public HelloModel hello() {
033 *     return new HelloModel("Spring Boot is now JStachioed!");
034 * }
035 * </code> </pre>
036 *
037 * @author agentgt
038 *
039 */
040public class JStachioHttpMessageConverter extends AbstractHttpMessageConverter<Object> {
041
042        private final JStachio jstachio;
043
044        /**
045         * Create http converter from jstachio
046         * @param jstachio an instance usually created by spring
047         */
048        public JStachioHttpMessageConverter(JStachio jstachio) {
049                super(StandardCharsets.UTF_8, MediaType.TEXT_HTML);
050                this.jstachio = jstachio;
051        }
052
053        @Override
054        protected boolean supports(Class<?> clazz) {
055                return jstachio.supportsType(clazz);
056        }
057
058        @Override
059        public boolean canRead(Class<?> clazz, @SuppressWarnings("exports") MediaType mediaType) {
060                return false;
061        }
062
063        @Override
064        protected Object readInternal(Class<? extends Object> clazz, HttpInputMessage inputMessage)
065                        throws IOException, HttpMessageNotReadableException {
066                throw new HttpMessageNotReadableException("Input not supported by JStachio", inputMessage);
067
068        }
069
070        @Override
071        protected void writeInternal(Object t, HttpOutputMessage outputMessage)
072                        throws IOException, HttpMessageNotWritableException {
073                Charset charset = getDefaultCharset();
074                if (charset == null) {
075                        charset = StandardCharsets.UTF_8;
076                }
077                try (Writer writer = new BufferedWriter(new OutputStreamWriter(outputMessage.getBody(), charset))) {
078                        jstachio.execute(t, writer);
079                }
080        }
081
082}