2

I got a bit stuck while taking my first baby steps with Custom Components in JavaServer Faces 2.2 (Jakarta Server Faces).

My problem is, how can a renderer class know, if a ConverterException was thrown? I need this check in my renderer, because I want the renderer to apply a 'invalid' class to the HTML input tag. The converter is used only for this Custom Component.

Here are some things I looked into, but I am not confident any of these this is the right approach.

  1. The method is isValidationFailed from FacesContext does not apply to conversion errors. So this is a dead end.

  2. I could create my own class from UIInput with a attribute 'invalid' and set this in the getAsObject method of the Converter class in case anything breaks. The renderer then checks the property of the component class.

  3. I could iterate over getMessages from FacesContext and look for a message from the converter.

  4. I can use the h:message approach and do some JavaScript DOM manipulation on the client side. If I find a h:message with a specific class, I apply another class to the input tag.

  5. Skip the renderer and do the rendering in the component class. Not sure if this gives me anything though.

Thanks in advance!

BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
raupach
  • 3,092
  • 22
  • 30
  • 1
    `UIInput` has already a `isValid()` method. Isn't this useable? – BalusC Jul 20 '20 at 13:11
  • @BalusC So I should go with the second approach? Extend from UIInput and setValid(false) in the converter class? – raupach Jul 20 '20 at 13:19
  • Oh? Is the converter attached to a non-`UIInput` component? That was unexpected. Why exactly this approach? – BalusC Jul 20 '20 at 13:26
  • @BalusC Because I did not know better and thought the setValid is only for validators and might have some other side effects. – raupach Jul 20 '20 at 13:33
  • I didn't mean that. You asked whether to extend from `UIInput`. This means that the component which you wanted to render with your custom renderer is not an `UIInput` at all. Only that was unexpected. – BalusC Jul 20 '20 at 13:36
  • @BalusC Sorry, for the confusion. I hope we don't talk past to each other. At first I only subclassed from UIOutput because I only wanted to display a value not read a value. That was before I knew UIInput subclasses UIOutput. – raupach Jul 20 '20 at 13:43
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/218216/discussion-between-bjorn-raupach-and-balusc). – raupach Jul 20 '20 at 13:43
  • Sorry, I'm now yet more confused. When exactly is the converter invoked? Was it invoked by the renderer itself? That's at least the default behavior for `UIOutput` components. You could just put a try-catch around it. I initially understood that the converter was invoked outside your control, which is indeed the default behavior for `UIInput`, but for `UIOutput`, while rendering the output value, the `getAsString()` converter is normally invoked by the very renderer itself via `getConvertedValue()` call and therefore fully under your control. – BalusC Jul 20 '20 at 14:18
  • I set the converter in the constructor of the custom component. – raupach Jul 20 '20 at 14:23
  • That's okay, but I was asking when the converter is invoked not when the converter is created/set. The `getAsObject()` is never invoked during output yet your question implies that it's invoked which in turn implies that you're interested in conversion during collecting a submitted input value (as that's when the `getAsObject()` is invoked). You just need to put a try-catch around the call to obtain the output value. – BalusC Jul 20 '20 at 14:24
  • I see. Maybe I should have added that the renderer subclasses HtmlBasicInputRenderer. Sorry for all the confusion. I really got a bit stuck with custom components and the inner workings. Does reading the JSF Spec help? – raupach Jul 20 '20 at 14:26
  • https://stackoverflow.com/questions/63068399/jsf-custom-components-is-it-nececssary-to-invoke-setvalidtrue-in-decode – raupach Jul 24 '20 at 06:59
  • Is it a good practice to delete this question now? I don't think my question made sense. – raupach Jul 24 '20 at 07:00
  • It was indeed confusing to start with, but in the end you appear to have an `UIOutput` component and you appear to be interested in the `getAsString()`. In this case simply put a try-catch around the call to it in the renderer. – BalusC Jul 24 '20 at 09:22

1 Answers1

1

Given these facts:

  • The component is an UIOutput.
  • You're interested in whether getAsString() throws an exception, and thus not whether getAsObject() throws an exception (that's only for UIInput components and it's normally only invoked when submitted input values need to be converted to bean properties).
  • The converter is (indirectly) invoked by the renderer.

Then the answer is to simply put the converter call in a try-catch. E.g.

Object modelValue = getValue();
String outputValue;

try {
    outputValue = getConverter().getAsString(context, component, modelValue);
}
catch (ConverterException e) {
    outputValue = "Conversion error occurred! " + e.getMessage();
}

responseWriter.write(outputValue);
BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555