I am wrapping Freemarker template loader in Spring MVC as described here to have default escaping in html pages.
So, I need to wrap content from java.io.Reader with my strings, not reading it, not converting it to string and not implementing myself. Is there class similar to WrappingReader or com.google.common.io.MultiReader (which is not public) in popular common libraries?
My implementation:
import com.google.common.io.CharStreams;
import com.google.common.io.InputSupplier;
...
private final TemplateLoader delegate;
@Autowired
public HtmlEscapingTemplateLoader(ResourceLoader resourceLoader)
{
delegate = new SpringTemplateLoader(resourceLoader, "/WEB-INF/templates/");
}
@Override
public Reader getReader(Object templateSource, String encoding) throws IOException
{
// collecting readers
Reader prologue = new StringReader("<#escape x as x?html>");
Reader originalReader = delegate.getReader(templateSource, encoding);
Reader epilogue = new StringReader("</#escape>");
// concatenating readers
return merge(prologue, originalReader, epilogue);
}
protected Reader merge(Reader prologue, Reader originalReader, Reader epilogue) throws IOException
{
return CharStreams.join(
Arrays.asList(new ReaderSupplier(prologue), new ReaderSupplier(originalReader), new ReaderSupplier(
epilogue))).getInput();
}
private static class ReaderSupplier
implements InputSupplier<Reader>
{
private final Reader reader;
public ReaderSupplier(Reader reader)
{
this.reader = reader;
}
@Override
public Reader getInput() throws IOException
{
return reader;
}
}
CharStreams i use is marked as @com.google.common.annotations.Beta. So, could it be rewritten in more solid way without usage of CharStreams?
Guava contributor here. ...Okay.
@Beta
does not mean "not fully tested" or "not widely used." The only thing it means is that we're not quite sure we're ready to freeze the API. That's only a problem if you're developing a library, or planning to upgrade versions of Guava later. (Also, honestly, CharStreams
is about as stable as @Beta
APIs get...)
You should not have a ReaderSupplier
class, which defeats the whole point of the InputSupplier
interface. For this particular case, instead of passing around Reader
s, you should be passing around InputSupplier<Reader>
s. In this particular case, CharStreams.newReaderSupplier(String)
returns an InputSupplier
that produces StringReader
s, so that fits this use case perfectly.
In any event, my complete implementation would be something like:
static final String prologue = "<#escape x as x?html>";
static final String epilogue = "</#escape>";
// ideally you shouldn't be passing around Readers at all
// the point of InputSupplier, etc. is that you should never get direct access
// to the Reader directly, so you don't have to track whether it's closed or not
public InputSupplier<Reader> getReaderSupplier(
final Object templateSource, final String encoding) {
return CharStreams.join(
CharStreams.newReaderSupplier(prologue),
new InputSupplier<Reader>() {
public Reader getInput() {
return delegate.getReader(templateSource, encoding);
}
},
CharStreams.newReaderSupplier(epilogue));
}
I am only answering the question: How to merge java.io.Reader's.
Using plain Java I was able to come up with the solution of using SequenceInputStream
on InputStreams
, which seems to be the better solution for merging two InputStreams
. See this stackoverflow question for merging InputStreams. Idea is simple: convert readers into InputStreams
, merge those and save the InputStream
into a Reader
.
Reader reader1 = new StringReader("String1");
Reader reader2 = new StringReader("String2");
ReaderInputStream readInputStream1 = new ReaderInputStream(reader1, StandardCharsets.UTF_8)
ReaderInputStream readInputStream2 = new ReaderInputStream(reader2, StandardCharsets.UTF_8)
Reader merged = new InputStreamReader(new SequenceInputStream(readInputStream1,readInputStream2), StandardCharsets.UTF_8);
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.