سؤال

Suppose I have a Java class Formatter with a static method format that does some simple text processing. I'd like to write a component that will pass the text within the component to the Formatter#format method, like so:

<test:format>
  Hello, #{user.name}!
</test:format>

For the sake of argument, suppose Formatter looks like this (in reality it's a Markdown library):

public class Formatter {
  public static format(String s) { return s.toUpperCase(); }
}

I'd like the rendered result of the above tag to be HELLO, DANIEL!.

Is this feasible? What do I need to do to get at the rendered text content under a component to process like this?

هل كانت مفيدة؟

المحلول

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.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top