jsf converter loses injected property - spring

I had this working before, but then I changed some things, and I can't get it to work again. I am trying to use my service tier to hit the database and get a correct object from my converter class, depending on what the user clicks. I inject the service property into my converter with spring. During debugging, I can see that the property gets sets properly. But then when I go to call getService, it is null.
#FacesConverter("PlaceConverter")
#SessionScoped
public class PlaceConverter implements Converter {
private SearchQueryService searchQueryService;
/**
* #return the searchQueryService
*/
public SearchQueryService getSearchQueryService() {
return searchQueryService;
}
/**
* #param searchQueryService the searchQueryService to set
*/
public void setSearchQueryService(SearchQueryService searchQueryService) {
this.searchQueryService = searchQueryService;
}
#Override
public Object getAsObject(FacesContext arg0, UIComponent arg1, String submittedValue) {
try {
Criteria criteria = new Criteria();
criteria.setId(Integer.parseInt(submittedValue));
return getSearchQueryService().findPlaces(criteria).get(0);
} catch (NumberFormatException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
#Override
public String getAsString(FacesContext arg0, UIComponent arg1, Object value) {
((Place) value).setCategory(" (" + ((Place) value).getCategory() + ")");
return String.valueOf(((Place) value).getPlaceId());
}
}
<bean id="placeConverterBean" class="com.ghghg.converter.PlaceConverter">
<property name="searchQueryService" ref="searchQueryServiceBean" />
</bean>

Dependency injection in a converter works only if the converter is declared as a managed bean by the dependency injection framework in question. E.g. JSF's own #ManagedBean, or CDI's #Named, or Spring's #Component. You should remove the #FacesConverter altogether and reference the converter instance in EL scope instead of referencing it by the converter ID.
Thus, so
<h:inputXxx converter="#{placeConverter}" />
or
<f:converter binding="#{placeConverter}" />
instead of
<h:inputXxx converter="PlaceConverter" />
or
<f:converter converterId="PlaceConverter" />
Your concrete problem suggests that you were referencing it by converter ID (thus, via #FacesConverter). This way you end up getting a converter instance without any injected dependencies.
See also:
How to inject Spring bean into JSF converter
As to the role of the converter itself, this is mandatory because HTML code is represented as one large string and HTTP request parameter values can only be represented as strings. Complex Java objects would otherwise be printed via Object#toString() like so com.example.Place#hashcode, making it unusable in the server side.

I found a better way, and probably more proper way to do get what I wanted. I was not completely sure how the converter works and how the value of the selected item gets passed back to the managed bean. I just declared a new Place object in my method, set the required values. Then I saw that it got passed to my managed bean

I got it to work like this in java EE with jsf 2.0. By making the converter a member of the backing bean. I instantiate this member using CDI but it should work the same with spring.
First the backing bean:
#ViewScoped
#ManagedBean
public class SomeView implements Serializable {
private static final long serialVersionUID = 1L;
#Inject
private SomeConverter converter;
public Converter getConverter() {
return converter;
}
}
And then this is the jsf xhtml:
<p:selectOneMenu id="someId" value="#{someView.value}" converter="#{someView.converter}">
<f:selectItems value="#{someView.values}" var="object" itemLabel="#{object.name}" />
</p:selectOneMenu>

Converter comes to play before updating your model bean. When user fill some input and this value is transferred to server first are updated your server side components and next conversion has happened. Converted values as saved in your bean (with method getAsObject) and before rendering the view values from beans are again converted to String because from user side everything is a string (then method getAsString is invoked).
In summary - Converter methods are the best place to change user input into your application logic, bean fields and in other way to convert your logic, bean fields into user friendly strings.
Due to your question and problem. You mean that SearchQueryService isn't available inside getAsObject method. Try to add an addnotation #Resource with proper name attribute and then it should be injected by your container.

Related

How to validate empty and not repeated jsf [duplicate]

I have Bean validation working nicely in my application. Now I want to check that a new user does not choose a username that has already been chosen.
In the actionlistener I have the code that checks the database but how do I force the user to be sent back to the page they were on if they choose an already existing username?
Introduction
You can do it, but JSF ajax/action/listener methods are semantically the wrong place to do validation. You actually don't want to get that far in JSF lifecycle if you've wrong input values in the form. You want the JSF lifecycle to stop after JSF validations phase.
You want to use a JSR303 Bean Validation annotation (#NotNull and friends) and/or constraint validator, or use a JSF Validator (required="true", <f:validateXxx>, etc) for that instead. It will be properly invoked during JSF validations phase. This way, when validation fails, the model values aren't updated and the business action isn't invoked and you stay in the same page/view.
As there isn't a standard Bean Validation annotation or JSF Validator for the purpose of checking if a given input value is unique according the database, you'd need to homegrow a custom validator for that.
I'll for both ways show how to create a custom validator which checks the uniqueness of the username.
Custom JSR303 Bean Validation Annotation
First create a custom #Username constraint annotation:
#Constraint(validatedBy = UsernameValidator.class)
#Documented
#Retention(RetentionPolicy.RUNTIME)
#Target({ElementType.FIELD, ElementType.METHOD, ElementType.ANNOTATION_TYPE})
public #interface Username {
String message() default "Username already exists";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
With this constraint validator (note: #EJB or #Inject inside a ConstraintValidator works only since CDI 1.1; so if you're still on CDI 1.0 then you'd need to manually grab it from JNDI):
public class UsernameValidator implements ConstraintValidator<Username, String> {
#EJB
private UserService service;
#Override
public void initialize(Username constraintAnnotation) {
// If not on CDI 1.1 yet, then you need to manually grab EJB from JNDI here.
}
Override
public boolean isValid(String username, ConstraintValidatorContext context) {
return !service.exist(username);
}
}
Finally use it as follows in model:
#Username
private String username;
Custom JSF Validator
An alternative is to use a custom JSF validator. Just implement the JSF Validator interface:
#ManagedBean
#RequestScoped
public class UsernameValidator implements Validator {
#EJB
private UserService userService;
#Override
public void validate(FacesContext context, UIComponent component, Object submittedAndConvertedValue) throws ValidatorException {
String username = (String) submittedAndConvertedValue;
if (username == null || username.isEmpty()) {
return; // Let required="true" or #NotNull handle it.
}
if (userService.exist(username)) {
throw new ValidatorException(new FacesMessage("Username already in use, choose another"));
}
}
}
Finally use it as follows in view:
<h:inputText id="username" ... validator="#{usernameValidator}" />
<h:message for="username" />
Note that you'd normally use a #FacesValidator annotation on the Validator class, but until the upcoming JSF 2.3, it doesn't support #EJB or #Inject. See also How to inject in #FacesValidator with #EJB, #PersistenceContext, #Inject, #Autowired.
Yes you can. You can do validation in action listener method, add faces messages if your custom validation failed, then call FacesContext.validationFailed() just before return.
The only problem with this solution is, it happens after the JSF validation and bean validation. I.e., it is after the validation phase. If you have multiple action listeners, say listener1 and listener2: if your custom validation in listener1 failed, it will continue to execute listener2. But after all, you'll get validationFailed in AJAX response.
It's better to use action method instead of actionListener for this purpose. Then you can return null (reloads page that triggered the action) from this method if the username exists. Here's an example:
in the facelet:
<h:commandButton action="#{testBean.doAction}" value="and... Action"/>
in the bean:
public String doAction() {
if (userExists) {
return null;
} else {
// go on processing ...
}
}
If you want to provide feedback to end-user:
xhtml:
<p:commandButton value="Go" process="#this" action="#{myBean.checkEntity()}" oncomplete="if(args.validationFailed){PF('widgetOldInfoNotice').show();}"/>
<p:confirmDialog id="dialogOldInfoNotice" header="NOTICE" severity="alert" widgetVar="widgetOldInfoNotice">
-- feedback message--
<p:button value="Ok" onclick="PF('widgetOldInfoNotice').hide();"/>
</p:confirmDialog>
bean:
public String checkEntity() {
if (!dao.whateverActionToValidateEntity(selectedEntity)) {
FacesContext context = FacesContext.getCurrentInstance();
context.validationFailed();
return "";
}
return "myPage.xhtml";
}
You can define a navigation case in the faces-config.xml file. This will allow you to redirect the user to a given page depending on the return value of the bean.
In the example below a suer is redirected to one of two pages depending on the return value of "myMethod()".
<navigation-rule>
<from-view-id>/index.xhtml</from-view-id>
<navigation-case>
<from-action>#{myBean.myMethod()}</from-action>
<from-outcome>true</from-outcome>
<to-view-id>/correct.xhtml</to-view-id>
</navigation-case>
<navigation-case>
<from-action>#{myBean.myMethod()}</from-action>
<from-outcome>false</from-outcome>
<to-view-id>/error.xhtml</to-view-id>
</navigation-case>
</navigation-rule>

Understanding JSF-validators. Do I really need one in this case? [duplicate]

I have Bean validation working nicely in my application. Now I want to check that a new user does not choose a username that has already been chosen.
In the actionlistener I have the code that checks the database but how do I force the user to be sent back to the page they were on if they choose an already existing username?
Introduction
You can do it, but JSF ajax/action/listener methods are semantically the wrong place to do validation. You actually don't want to get that far in JSF lifecycle if you've wrong input values in the form. You want the JSF lifecycle to stop after JSF validations phase.
You want to use a JSR303 Bean Validation annotation (#NotNull and friends) and/or constraint validator, or use a JSF Validator (required="true", <f:validateXxx>, etc) for that instead. It will be properly invoked during JSF validations phase. This way, when validation fails, the model values aren't updated and the business action isn't invoked and you stay in the same page/view.
As there isn't a standard Bean Validation annotation or JSF Validator for the purpose of checking if a given input value is unique according the database, you'd need to homegrow a custom validator for that.
I'll for both ways show how to create a custom validator which checks the uniqueness of the username.
Custom JSR303 Bean Validation Annotation
First create a custom #Username constraint annotation:
#Constraint(validatedBy = UsernameValidator.class)
#Documented
#Retention(RetentionPolicy.RUNTIME)
#Target({ElementType.FIELD, ElementType.METHOD, ElementType.ANNOTATION_TYPE})
public #interface Username {
String message() default "Username already exists";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
With this constraint validator (note: #EJB or #Inject inside a ConstraintValidator works only since CDI 1.1; so if you're still on CDI 1.0 then you'd need to manually grab it from JNDI):
public class UsernameValidator implements ConstraintValidator<Username, String> {
#EJB
private UserService service;
#Override
public void initialize(Username constraintAnnotation) {
// If not on CDI 1.1 yet, then you need to manually grab EJB from JNDI here.
}
Override
public boolean isValid(String username, ConstraintValidatorContext context) {
return !service.exist(username);
}
}
Finally use it as follows in model:
#Username
private String username;
Custom JSF Validator
An alternative is to use a custom JSF validator. Just implement the JSF Validator interface:
#ManagedBean
#RequestScoped
public class UsernameValidator implements Validator {
#EJB
private UserService userService;
#Override
public void validate(FacesContext context, UIComponent component, Object submittedAndConvertedValue) throws ValidatorException {
String username = (String) submittedAndConvertedValue;
if (username == null || username.isEmpty()) {
return; // Let required="true" or #NotNull handle it.
}
if (userService.exist(username)) {
throw new ValidatorException(new FacesMessage("Username already in use, choose another"));
}
}
}
Finally use it as follows in view:
<h:inputText id="username" ... validator="#{usernameValidator}" />
<h:message for="username" />
Note that you'd normally use a #FacesValidator annotation on the Validator class, but until the upcoming JSF 2.3, it doesn't support #EJB or #Inject. See also How to inject in #FacesValidator with #EJB, #PersistenceContext, #Inject, #Autowired.
Yes you can. You can do validation in action listener method, add faces messages if your custom validation failed, then call FacesContext.validationFailed() just before return.
The only problem with this solution is, it happens after the JSF validation and bean validation. I.e., it is after the validation phase. If you have multiple action listeners, say listener1 and listener2: if your custom validation in listener1 failed, it will continue to execute listener2. But after all, you'll get validationFailed in AJAX response.
It's better to use action method instead of actionListener for this purpose. Then you can return null (reloads page that triggered the action) from this method if the username exists. Here's an example:
in the facelet:
<h:commandButton action="#{testBean.doAction}" value="and... Action"/>
in the bean:
public String doAction() {
if (userExists) {
return null;
} else {
// go on processing ...
}
}
If you want to provide feedback to end-user:
xhtml:
<p:commandButton value="Go" process="#this" action="#{myBean.checkEntity()}" oncomplete="if(args.validationFailed){PF('widgetOldInfoNotice').show();}"/>
<p:confirmDialog id="dialogOldInfoNotice" header="NOTICE" severity="alert" widgetVar="widgetOldInfoNotice">
-- feedback message--
<p:button value="Ok" onclick="PF('widgetOldInfoNotice').hide();"/>
</p:confirmDialog>
bean:
public String checkEntity() {
if (!dao.whateverActionToValidateEntity(selectedEntity)) {
FacesContext context = FacesContext.getCurrentInstance();
context.validationFailed();
return "";
}
return "myPage.xhtml";
}
You can define a navigation case in the faces-config.xml file. This will allow you to redirect the user to a given page depending on the return value of the bean.
In the example below a suer is redirected to one of two pages depending on the return value of "myMethod()".
<navigation-rule>
<from-view-id>/index.xhtml</from-view-id>
<navigation-case>
<from-action>#{myBean.myMethod()}</from-action>
<from-outcome>true</from-outcome>
<to-view-id>/correct.xhtml</to-view-id>
</navigation-case>
<navigation-case>
<from-action>#{myBean.myMethod()}</from-action>
<from-outcome>false</from-outcome>
<to-view-id>/error.xhtml</to-view-id>
</navigation-case>
</navigation-rule>

Primefaces dataTable with commandButton send multiple request to hibernate [duplicate]

Let's say I specify an outputText component like this:
<h:outputText value="#{ManagedBean.someProperty}"/>
If I print a log message when the getter for someProperty is called and load the page, it is trivial to notice that the getter is being called more than once per request (twice or three times is what happened in my case):
DEBUG 2010-01-18 23:31:40,104 (ManagedBean.java:13) - Getting some property
DEBUG 2010-01-18 23:31:40,104 (ManagedBean.java:13) - Getting some property
If the value of someProperty is expensive to calculate, this can potentially be a problem.
I googled a bit and figured this is a known issue. One workaround was to include a check and see if it had already been calculated:
private String someProperty;
public String getSomeProperty() {
if (this.someProperty == null) {
this.someProperty = this.calculatePropertyValue();
}
return this.someProperty;
}
The main problem with this is that you get loads of boilerplate code, not to mention private variables that you might not need.
What are the alternatives to this approach? Is there a way to achieve this without so much unnecessary code? Is there a way to stop JSF from behaving in this way?
Thanks for your input!
This is caused by the nature of deferred expressions #{} (note that "legacy" standard expressions ${} behave exactly the same when Facelets is used instead of JSP). The deferred expression is not immediately evaluated, but created as a ValueExpression object and the getter method behind the expression is executed everytime when the code calls ValueExpression#getValue().
This will normally be invoked one or two times per JSF request-response cycle, depending on whether the component is an input or output component (learn it here). However, this count can get up (much) higher when used in iterating JSF components (such as <h:dataTable> and <ui:repeat>), or here and there in a boolean expression like the rendered attribute. JSF (specifically, EL) won't cache the evaluated result of the EL expression at all as it may return different values on each call (for example, when it's dependent on the currently iterated datatable row).
Evaluating an EL expression and invoking a getter method is a very cheap operation, so you should generally not worry about this at all. However, the story changes when you're performing expensive DB/business logic in the getter method for some reason. This would be re-executed everytime!
Getter methods in JSF backing beans should be designed that way that they solely return the already-prepared property and nothing more, exactly as per the Javabeans specification. They should not do any expensive DB/business logic at all. For that the bean's #PostConstruct and/or (action)listener methods should be used. They are executed only once at some point of request-based JSF lifecycle and that's exactly what you want.
Here is a summary of all different right ways to preset/load a property.
public class Bean {
private SomeObject someProperty;
#PostConstruct
public void init() {
// In #PostConstruct (will be invoked immediately after construction and dependency/property injection).
someProperty = loadSomeProperty();
}
public void onload() {
// Or in GET action method (e.g. <f:viewAction action>).
someProperty = loadSomeProperty();
}
public void preRender(ComponentSystemEvent event) {
// Or in some SystemEvent method (e.g. <f:event type="preRenderView">).
someProperty = loadSomeProperty();
}
public void change(ValueChangeEvent event) {
// Or in some FacesEvent method (e.g. <h:inputXxx valueChangeListener>).
someProperty = loadSomeProperty();
}
public void ajaxListener(AjaxBehaviorEvent event) {
// Or in some BehaviorEvent method (e.g. <f:ajax listener>).
someProperty = loadSomeProperty();
}
public void actionListener(ActionEvent event) {
// Or in some ActionEvent method (e.g. <h:commandXxx actionListener>).
someProperty = loadSomeProperty();
}
public String submit() {
// Or in POST action method (e.g. <h:commandXxx action>).
someProperty = loadSomeProperty();
return "outcome";
}
public SomeObject getSomeProperty() {
// Just keep getter untouched. It isn't intented to do business logic!
return someProperty;
}
}
Note that you should not use bean's constructor or initialization block for the job because it may be invoked multiple times if you're using a bean management framework which uses proxies, such as CDI.
If there are for you really no other ways, due to some restrictive design requirements, then you should introduce lazy loading inside the getter method. I.e. if the property is null, then load and assign it to the property, else return it.
public SomeObject getSomeProperty() {
// If there are really no other ways, introduce lazy loading.
if (someProperty == null) {
someProperty = loadSomeProperty();
}
return someProperty;
}
This way the expensive DB/business logic won't unnecessarily be executed on every single getter call.
See also:
Why is the getter called so many times by the rendered attribute?
Invoke JSF managed bean action on page load
How and when should I load the model from database for h:dataTable
How to populate options of h:selectOneMenu from database?
Display dynamic image from database with p:graphicImage and StreamedContent
Defining and reusing an EL variable in JSF page
Measure the render time of a JSF view after a server request
With JSF 2.0 you can attach a listener to a system event
<h:outputText value="#{ManagedBean.someProperty}">
<f:event type="preRenderView" listener="#{ManagedBean.loadSomeProperty}" />
</h:outputText>
Alternatively you can enclose the JSF page in an f:view tag
<f:view>
<f:event type="preRenderView" listener="#{ManagedBean.loadSomeProperty}" />
.. jsf page here...
<f:view>
I have written an article about how to cache JSF beans getter with Spring AOP.
I create a simple MethodInterceptor which intercepts all methods annotated with a special annotation:
public class CacheAdvice implements MethodInterceptor {
private static Logger logger = LoggerFactory.getLogger(CacheAdvice.class);
#Autowired
private CacheService cacheService;
#Override
public Object invoke(MethodInvocation methodInvocation) throws Throwable {
String key = methodInvocation.getThis() + methodInvocation.getMethod().getName();
String thread = Thread.currentThread().getName();
Object cachedValue = cacheService.getData(thread , key);
if (cachedValue == null){
cachedValue = methodInvocation.proceed();
cacheService.cacheData(thread , key , cachedValue);
logger.debug("Cache miss " + thread + " " + key);
}
else{
logger.debug("Cached hit " + thread + " " + key);
}
return cachedValue;
}
public CacheService getCacheService() {
return cacheService;
}
public void setCacheService(CacheService cacheService) {
this.cacheService = cacheService;
}
}
This interceptor is used in a spring configuration file:
<bean id="advisor" class="org.springframework.aop.support.DefaultPointcutAdvisor">
<property name="pointcut">
<bean class="org.springframework.aop.support.annotation.AnnotationMatchingPointcut">
<constructor-arg index="0" name="classAnnotationType" type="java.lang.Class">
<null/>
</constructor-arg>
<constructor-arg index="1" value="com._4dconcept.docAdvance.jsfCache.annotation.Cacheable" name="methodAnnotationType" type="java.lang.Class"/>
</bean>
</property>
<property name="advice">
<bean class="com._4dconcept.docAdvance.jsfCache.CacheAdvice"/>
</property>
</bean>
Hope it will help!
Originally posted in PrimeFaces forum # http://forum.primefaces.org/viewtopic.php?f=3&t=29546
Recently, I have been obsessed evaluating the performance of my app, tuning JPA queries, replacing dynamic SQL queries with named queries, and just this morning, I recognized that a getter method was more of a HOT SPOT in Java Visual VM than the rest of my code (or majority of my code).
Getter method:
PageNavigationController.getGmapsAutoComplete()
Referenced by ui:include in in index.xhtml
Below, you will see that PageNavigationController.getGmapsAutoComplete() is a HOT SPOT (performance issue) in Java Visual VM. If you look further down, on the screen capture, you will see that getLazyModel(), PrimeFaces lazy datatable getter method, is a hot spot too, only when enduser is doing a lot of 'lazy datatable' type of stuff/operations/tasks in the app. :)
See (original) code below.
public Boolean getGmapsAutoComplete() {
switch (page) {
case "/orders/pf_Add.xhtml":
case "/orders/pf_Edit.xhtml":
case "/orders/pf_EditDriverVehicles.xhtml":
gmapsAutoComplete = true;
break;
default:
gmapsAutoComplete = false;
break;
}
return gmapsAutoComplete;
}
Referenced by the following in index.xhtml:
<h:head>
<ui:include src="#{pageNavigationController.gmapsAutoComplete ? '/head_gmapsAutoComplete.xhtml' : (pageNavigationController.gmaps ? '/head_gmaps.xhtml' : '/head_default.xhtml')}"/>
</h:head>
Solution: since this is a 'getter' method, move code and assign value to gmapsAutoComplete prior to method being called; see code below.
/*
* 2013-04-06 moved switch {...} to updateGmapsAutoComplete()
* because performance = 115ms (hot spot) while
* navigating through web app
*/
public Boolean getGmapsAutoComplete() {
return gmapsAutoComplete;
}
/*
* ALWAYS call this method after "page = ..."
*/
private void updateGmapsAutoComplete() {
switch (page) {
case "/orders/pf_Add.xhtml":
case "/orders/pf_Edit.xhtml":
case "/orders/pf_EditDriverVehicles.xhtml":
gmapsAutoComplete = true;
break;
default:
gmapsAutoComplete = false;
break;
}
}
Test results: PageNavigationController.getGmapsAutoComplete() is no longer a HOT SPOT in Java Visual VM (doesn't even show up anymore)
Sharing this topic, since many of the expert users have advised junior JSF developers to NOT add code in 'getter' methods. :)
If you are using CDI, you can use Producers methods.
It will be called many times, but the result of first call is cached in scope of the bean and is efficient for getters that are computing or initializing heavy objects!
See here, for more info.
You could probably use AOP to create some sort of Aspect that cached the results of our getters for a configurable amount of time. This would prevent you from needing to copy-and-paste boilerplate code in dozens of accessors.
If the value of someProperty is
expensive to calculate, this can
potentially be a problem.
This is what we call a premature optimization. In the rare case that a profiler tells you that the calculation of a property is so extraordinarily expensive that calling it three times rather than once has a significant performance impact, you add caching as you describe. But unless you do something really stupid like factoring primes or accessing a databse in a getter, your code most likely has a dozen worse inefficiencies in places you've never thought about.
I would also advice using such Framework as Primefaces instead of stock JSF, they address such issues before JSF team e. g in primefaces you can set partial submit. Otherwise BalusC has explained it well.
It still big problem in JSF. Fo example if you have a method isPermittedToBlaBla for security checks and in your view you have rendered="#{bean.isPermittedToBlaBla} then the method will be called multiple times.
The security check could be complicated e.g . LDAP query etc. So you must avoid that with
Boolean isAllowed = null ... if(isAllowed==null){...} return isAllowed?
and you must ensure within a session bean this per request.
Ich think JSF must implement here some extensions to avoid multiple calls (e.g annotation #Phase(RENDER_RESPONSE) calle this method only once after RENDER_RESPONSE phase...)

Why is #PostConstruct method called after post/postback?

I have following request scoped Spring bean with #postconstruct method init():
#Component
#Scope("request")
public class editUserBB {
Map<String, String> params = FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap();
private UserDto user;
#Autowired
private IUserService userService;
#PostConstruct
public void init() throws IOException {
String id_string = params.get("id");
Long id = Long.parseLong(id_string);
user = userService.getUserById(id);
}
public String save(){
// save to database
return "user?faces-redirect=true&id=" + (long)user.getId();
}
}
And userEdit.xhtml with h:form and commandButton:
<h:commandButton value="Save" action="#{editUserBB.save()}" />
However, after the save button is clicked the init() method is called once again annulling all the changes made to the UserDto object before I can save it to the DB. So what am I doing wrong?
And I just tested, the init() method is called even before save(), which I also don't understand..
That's not the fault of the init() method. That's just your own fault of placing the bean in the request scope instead of in the view scope.
A request scoped bean lives as long as a single HTTP request-response cycle. Opening the page with the form counts as one HTTP request. The HTTP request is garbaged when the associated HTTP response is finished sending the result to the client, including all associated request scoped beans. Submitting the form counts as another HTTP request which thus creates a completely new instance of the request scoped bean. If you explore/debug the instance's hashcode (and constructor), you'll notice that it are actually two physically completely distinct instances. There's thus absolutely no means of the init() to "override" the old values. The old values aren't there in first place.
JSF has solved this awkward behavior of a request scoped bean with introducing the view scope. You probably have ever heard/read about it before replacing JSF bean management facility by Spring's one for some reason. Spring bean management facility doesn't have a native concept of the view scope, you'd need to homegrow one.
If you intend to stick to Spring bean management facility, then your best bet is retaining the request parameter responsible for proper initialization of the data along with the form submit. You can use <f:param> for that:
<h:commandButton value="Save" action="#{editUserBB.save()}">
<f:param name="id" value="#{param.id}" />
</h:commandButton>
See also:
How to choose the right bean scope?
How do request/session/application work?
Unrelated to the concrete problem, you should avoid calling FacesContext during instance construction/initialization. This is bad design. In this particular case, move that line of obtaining the request parameter map to inside the init() method. Also here, JSF bean management facility has a standard solution in flavor of #ManagedProperty while Spring one doesn't have.

Is it possible to annotate a backing bean method to be called on a phase?

I need an initializer method in the backing bean to be called after components are bind. #PostConstruct is called before component bindings. Is there any JSF annotation for methods which cause method call after component binding?
Currently it's possible to use something like <f:view afterPhase="#{bean.initialize}"> or <f:event type="preRenderView" listener="#{bean.initialize}" /> which requires code on page side and bean side. Is there any bean-side-only solution?
There's nothing like that in standard JSF API.
Closest what you can get is lazy loading in getter.
public UIComponent getSomeComponent() {
if (!initialized(someComponent)) {
initialize(someComponent);
}
return someComponent;
}
or lazy executing in setter.
public void setSomeComponent(UIComponent someComponent) {
if (!initialized(someComponent)) {
initialize(someComponent);
}
this.someComponent = someComponent;
}

Resources