I have figured out a way to do this, but I suspect it's a kludge. Code:
@FacesComponent("MyComponent")
public class MyComponent
extends UIComponentBase
implements NamingContainer {
@Override public String getFamily() {
return UINamingContainer.COMPONENT_FAMILY;
}
@Override public boolean getRendersChildren() { return true; }
@Override public void encodeChildren(FacesContext fc) throws IOException {
StringWriter writer = new StringWriter();
ResponseWriter rw = fc.getResponseWriter();
// create the response writer
ResponseWriter replacement = rw.cloneWithWriter(writer);
// this tag wrapping step is necessary for the MyFaces ResponseWriter to
// work correctly
replacement.startDocument();
replacement.startElement("div", this);
// mask the response writer temporarily
fc.setResponseWriter(replacement);
// perform the render to get the text in our string
super.encodeChildren(fc);
// unmask the response writer
fc.setResponseWriter(rw);
// finish the wrapping calls
replacement.endElement("div");
replacement.endDocument();
// this strips the rendered <div> tag wrapper from the generated text.
final String renderedText = writer.toString()
.substring(5, writer.toString().length()-6);
// process the text and send it out
rw.append(Formatter.format(renderedText));
}
}
This all hinges on the ResponseWriter#cloneWithWriter
method. However, if you just slap a StringWriter in there and expect it to go, MyFaces will blow up--you need to at least create a wrapping tag to create a safe context for the text to be rendered to. My formatter doesn't expect the wrapping element, so I remove that with a gross substring thing afterwards. Beyond that, implementing getRendersChildren
seems to be enough to make this go. You then hook this up with a taglib.xml.