Consider a custom UIComponent (for test purposes only):
public class UITest extends UIComponentBase {
#Override
public void encodeBegin(FacesContext context) throws IOException {
System.out.println("encodeBegin");
}
#Override
public void encodeAll(FacesContext context) throws IOException {
System.out.println("encodeAll");
}
}
When I add it to page inside a composite component, the encodeBegin() method gets called. However, when add it to page outside a composite component, the encodeAll() method gets called instead.
Adding it inside other UIComponents makes no difference, only composite component wrapper seems to change the behavior.
Couldn't find info why it is so? A link to the spec?
The spec is really messy in this case, stating that:
"These methods are called during the Render Response phase of the request processing lifecycle. encodeAll() will
cause this component and all its children and facets that return true from isRendered() to be rendered, regardless
of the value of the getRendersChildren() return value. encodeBegin(), encodeChildren(), and
encodeEnd()have the responsibility of creating the response data for the beginning of this component, this
component’s children (only called if the rendersChildren property of this component is true), and the ending of
this component, respectively."
However, this seems to be a mixture of new and old features, where the new functionality (encodeAll) seems to be incomplete in some ways:
I tried the following:
A) Calling the component directly in the page (no wrapper)
extend UIComponentBase (or other UIComponent class such as UIInput, UIOutput.. etc), declare it as a tag, and use it in the UI.
In this case the encodeAll method is called IF it is present (overridden), if not the encodeBegin and encodeEnd methods will be called!!
Another thing to note is that you can create a custom Renderer for the component, so you can separate rendering logic from behaviour. (by creating another class that extends Renderer, and annotating it with #FacesRenderer)
This is where it gets interesting; Renderer defines only encodeBegin, encodeChildren and encodeEnd (with no mention of encodeAll).
Now the logic seems to go roughly like this:
if (encodeAll is present)
encodeAll is called (and the renderer is ignored!)
else if(any of encodeBegin,Children,or end exist in the class that extends UIComponent)
call the method that was found in that component
else if(encodeBegin, children or end exist in the class that extends Renderer)
call the corresponding method that was found.
So this means that implementing encodeAll (or encodeBegin.. etc ) in the class extending UIComponent causes the renderer to be ignored!
B) Wrapping the component (cc:implementation.. etc)
In this case the same thing happened as above, except that encodeAll was not called in any case, no matter what I did.
Conclusion:
It seems that encodeAll is some kind of new functionality (or shortcut) to implement the rendering code, and it seems that cc:implementation has a bug in this case (it doesn't look for encodeAll).
I hope this is at least of some value to you, unfortunately I cannot provide a more thorough answer. :(
It also seems that nobody else knows about this.
Related
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.
The method is isValidationFailed from FacesContext does not apply to conversion errors. So this is a dead end.
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.
I could iterate over getMessages from FacesContext and look for a message from the converter.
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.
Skip the renderer and do the rendering in the component class. Not sure if this gives me anything though.
Thanks in advance!
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);
Seems basic enough...
I have a custom JSF component and its associated renderer. The renderer does the decode and encodeEnd.
In decode i successfully retrie the submitted value via component.setSubmittedValue(ctx.getExternalContext().getRequestParameterMap().get(c.getClientId()));
In encodeEnd, i basically create the markup and if component.getValue() is not null, i insert its contents in the markup. So far so good.
Problem is that getValue() can be only be String. I have custom class that represents a compound data type and i want to use that as the component's local value. But doesn't work - JSF converts to String.
I also tried using component.getAttributes() - from the decode method, where i put my custom object in keyed to private static final String someKey = "asd". But later at encodeEnd there is no value/key in the map.
I want the users of this component to be able to specify in their backing bean the custom data type and not worry about serialization/deserialization to text representation between client/server. Presumably i have to use a converter for that? But how can i set up a default and immutable converter for the custom component?
The problem has a simple enough of a solution. Inside the Renderer class (or right into the Component class if using that directly):
#Override
public Object getConvertedValue(FacesContext context, UIComponent component, Object submittedValue) throws ConverterException {
SomeCustomObject thing;
//... do magic to create SomeCustomObject based on submittedValue
return thing;
}
Now whenever getValue() is called on that component, SomeCustomObject will be returned and you can safely cast to it. Also in the backing beans can use SomeCustomObject as the type.
Also note when calling component.getValue() in the actual Renderer, it will return SomeCustomObject as well, so if you're restoring state, you must convert back to its String representation.
For more details see and #Kukeltje's answer above and check how the same thing is done for primefaces calendar component here: https://github.com/primefaces/primefaces/blob/master/src/main/java/org/primefaces/component/calendar/BaseCalendarRenderer.java
For another more concise and clear illustration, check #BalusC's answer as well.
I have a requirement where i need to weld a ContentPart to all the content types. Please guide me what is the best place to write this code.
I looked into the Orchard source code where InfosetPart is being welded with all content types in ContentHandlerBase's Activating method.
Following the InfosetPart weld mechanism i created one class inheriting from ContentHandlerBase and in Activating method i placed a break point with following condition which is getting hit again and again (more than once for one content type)
context.ContentType == "Page"
I'm not sure if it should be as it is because ideally it should hit this condition only once.
The way you are implementing it is correct. Your code is executed multiple times because content handlers are invoked for each content item, and not just for the content type. This also allows you to weld your part to only some of you content items, not all items of a specified type.
You wrote that you created a subclass of ContentHandlerBase. You should use ContentHandler as a base class.
Below is a simple code example how this should be done.
public class MyPartHandler : ContentHandler
{
protected override void Activating(ActivatingContentContext context) {
context.Builder.Weld<MyPart>();
}
}
WHAT I HAVE is a standard JavaFX application: Main.java, MainController.java & main.fxml. To add custom component, I created CustomComponentController.java and custom_component_controller.fxml.
PROBLEM is that in CustomComponentController methods I need to reference other methods and standard components from MenuController. I add public static MainController mc; to MainController class body, so that it can be seen from CustomComponentController (MainController.mc.neededMethod()). Then I try to pass everything to it in MainController.initialize() method (mc = this;) - when debugging this breakpoint, I see this full of components instances, but mc remains with null components afterwards.
QUESTION is how to reference the running instance of MainController to use its components and methods in other classes and to crossreference different custom components from each other? How to clean MainController code from event handlers and assistance methods of components by moving it all to component's own class?
I tried the following approaches, but found no way to make them work without errors:
Accessing FXML controller class
How can I access a Controller class in JavaFx 2.0?
JavaFX 2.0 + FXML. Updating scene values from a different Task
JavaFX 2.2 -fx:include - how to access parent controller from child controller
The problem can be solved if you comply the following conditions:
Not only public, but obligatory static MainController mc should be.
Do not forget id in fxml for CustomComponentController: <CustomComponentController fx:id="cc"/>, where cc is the name of the "#FXML imported" CustomComponentController in your MainController class.
Omit parameter fx:controller="main.CustomComponentController" in custom_component_controller.fxml as it results in "Controller value already specified" error (a conflict between main.fxml and custom_component_controller.fxml markup declared controllers).
Put mc = this; in the beginning of MainController's initialize() method. Before using mc in CustomComponentController class, check if it's not null. It can be null when all components, including CustomComponentController, are instantiated at application startup, but there is no mc instance yet. MainController method initialize() where MainController is instantiated is called after components are loaded. Therefore better practice is to use approach in the next paragraph.
In main.fxml create primary component of the same type that CustomComponentController and with the only fx:id parameter. Replace primary component with your CustomComponentController by creating reloadCustomComponents() method and calling it from CustomComponentController's initialize() method. Do it by adding the following to reloadCustomComponents() method:
customComponentAnchorPane.getChildren().remove(customComponent);
customComponent = new customComponent();
customComponentAnchorPane.getChildren().add(customComponent);
Thus all components can be placed outside CustomComponentController with all their methods and reloaded at the startup of the apllication. All component declarations stay in MainController class and can be reached through MainController mc reference. No duplicate creating of components in detail with parameters is needed.
Your problem looks like the classic catalog-crud forms updating, I implemented an interface that I called Updatable with an update method so I could reference any catalog form with any crud form easy after passing Controller Main Class as the UserData Property of the Child Root Component's Form
Hope it Can Solve your problem
I am developing webapp where my MVC controller is JSF 2.1. I have several methods that are based on
FacesContext.getCurrentInstance()
I use this to
put/retrieve values from Flash scope
add messages on view
get request params map
examples:
public void addInfoMessage(String title, String description){
FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_INFO,title, description));
}
and
public void putFlashMessage(String code, String value){
FacesContext.getCurrentInstance().getExternalContext().getFlash().put(code, value);
}
etc.
I'm just wondering where is proper place to put this methods if I use this on every single managed bean? I consider two options:
a) create class "JSFUtils", where all method are public and static
b) create super class "ManagedBean" with no declared scope and no declared #ManagedBean annotation, but with these public methods. Every managed bean should be child of these class so it will have inherited these methods.
An utility class is the recommended approach. Instead of reinventing your own, you can use an existing JSF utility library, such as OmniFaces which has Faces and Messages utility classes for the purpose.
String foo = Faces.getRequestParameter("foo");
Messages.create(summary).detail(detail).add();
Messages.addGlobalInfo(summary); // Without detail.
Faces.setFlashAttribute(key, value);
You can indeed also abstract it away as a "super bean", but this is not reusable and you would keep repeating yourself in every JSF project. Also, a class can extend from only one class. So if your bean happen to need to extend from another super class, then you're lost.
I would recommend a utility class for the purpose simply because you allow the flexibility to extend other useful classes, such as those that have some common logic that you'd like to share across other beans.
Having said that, a JSFUtils class can grow quite cluttered with time with many many methods and can become very unmanageable. It would be better to categorize the util methods and put them in separate static utility classes.