0

I have an issue with a customer converter I have written. I am calling my DAL from converter and injecting it as a managed property. When I call the converter from one of my ui components everything works properly; however when I call it from another component the injected DAL is null. I apologize if this is a dupe, I have looked all over the place to find an answer.

I am using primefaces 3.5.

Here is the converter:

@ManagedBean(name = "fanlistConverter")
public class FanlistConverter implements Converter, Serializable {
private  List<Fanlist> fanlist; 
@ManagedProperty(value="#{dAL}")
private DAL dAL;
private static Session session;


public FanlistConverter(){

} 

@PostConstruct
public void init(){
    session  = dAL.getSession();

}




public Object getAsObject(FacesContext facesContext, UIComponent component, String submittedValue) {  
    if (!submittedValue.equals(null) &&  !submittedValue.equals("null")) {  
        Fanlist fanlist = new Fanlist();

        try {  

                fanlist = (Fanlist)session.get(Fanlist.class, UUID.fromString(submittedValue));


            } catch(NumberFormatException exception) {  
                System.out.println("error: " + exception.getMessage());
                throw new ConverterException(new FacesMessage(FacesMessage.SEVERITY_ERROR, "Conversion Error", "Not a valid player"));  
            }catch(Exception e){
                System.out.println("error get as Object: " + e.getMessage());

            }


    } 

   return  fanlist; 


}  

 public String getAsString(FacesContext facesContext, UIComponent component, Object value) {  
        if (value == null || value.equals("")) {  
            return "";  
        } else {  
            return String.valueOf(((Fanlist) value).getId());  
        }  
    }   



public DAL getdAL() {
    return dAL;
}

public void setdAL(DAL dAL) {
    this.dAL = dAL;
}  

}

and here are the two ui components

this one works:

                <p:panelGrid columns="3">
                    <p:outputLabel for="fanlist" value="Subscription Opt-In List    " />
                    <p:autoComplete id="fanlist" dropdown="true"
                        value="#{campaignWizard.selectedList}"
                        completeMethod="#{campaignWizard.complete}" var="f"
                        itemLabel="#{f.name}" itemValue="#{f}" converter="#{fanlistConverter}" />
                    <p:commandLink value="Add List"
                        actionListener="#{campaignWizard.addFanList}" update=":formbox2"
                        ajax="false" />
                </p:panelGrid>

and this one does not work

        <p:selectManyMenu id="fanlist2" value="#{blast.selectedLists}"
                    var="fl" showCheckbox="true" converter="#{fanlistConverter}"
                    style="width:250px;height:100px">
                    <f:selectItems value="#{blast.fanlists}" var="fanl"
                        itemLabel="#{fanl.name}" itemValue="#{fanl}" />
                    <p:column>
                        Name: #{fl.name} 
                        </p:column>
                    <p:column>
                        Size: #{fl.name}
                        </p:column>
                </p:selectManyMenu>




@ManagedBean(name = "blast")
@ViewScoped
public class BlastBean implements Serializable {
@ManagedProperty(value="#{globalVars}")
private GlobalVars globalVars; 

@ManagedProperty(value="#{dAL}")
private DAL dAL;

@ManagedProperty(value="#{messaging}")
private Messaging messaging; 

private User u; 
private Blast blast;
private List<Fanlist> fanlists; 
private List<Fanlist> selectedLists;
private List<Fanlisttoparent> fltops = new ArrayList<Fanlisttoparent>();

    public  BlastBean(){


}

@PostConstruct
public void init(){

    fetchData();


}

public void fetchData(){
    u = globalVars.getUser();
    blast = new Blast();
    fanlists = dAL.query("FROM Fanlist where client.id ='" + globalVars.getUser().getClient().getId() + "'");

}   

...

public String sendBlast(){
    System.out.println("blast:" + blast.getMessage());
    dAL.upsert(blast);
    final List<String> phoneNumbers = new ArrayList<String>(); 

    List<Profile> profiles = new ArrayList<Profile>(); 
    for(Fanlist fl: selectedLists){
        Set<Fantolist> fantolist = fl.getFantolists();
        for(Fantolist ftol: fantolist){
            profiles.add(ftol.getFanprofile().getProfile());
        }

        for(Profile p: profiles){
            phoneNumbers.add("+1"+ p.getPhonenumber());
        }

    }



...
sgoldberg
  • 477
  • 2
  • 7
  • 18
  • Is it your `#{dAL}` available when you call it? What kind of Scope has it? Check it's being built before the injection happens. – Aritz Jan 23 '13 at 10:29
  • @XtremeBiker it is session scoped. It is being built on the login page and it is used on every Bean in my app, and this is the only place that is null. – sgoldberg Jan 23 '13 at 15:43
  • Add and `` tag and see if your bean is really into the lifecycle. http://stackoverflow.com/a/8269559/1199132 – Aritz Jan 23 '13 at 15:54

1 Answers1

1

First we need to understand when exactly Validation Error: Value is not valid would occur. This error will occur when the equals() test of the currently selected item has not returned true for any of the currently available items.

So, this error has technically 2 causes:

  1. The equals() method of the item type is missing or broken.

  2. The list of currently available items has incompatibly changed as compared to the initial request.

    And when a converter is involved, then there's a third cause:

  3. The converter has returned null instead of the desired object in getAsObject().

Based on the information provided so far, the converter works fine in one page, but not in other page. So cause 1 can safely be scratched. Left behind causes 2 and 3.

As to cause 2, you need to guarantee that the <f:selectItems value="#{blast.fanlists}"> doesn't return a different value during processing the form submit. This could happen if the #{blast} bean is request scoped and that the fanlists property is initialized based on some request scoped variable which is lost during the form submit. You can fix it by putting the bean in the view scope (and ensuring that you aren't doing business logic in getter).

As to cause 3, a debugger/logger should give sufficient clues whether the converter is properly doing its job. This problem is then actually beyond the scope of JSF. It's the responsibility of the developer to return the proper object instance based on the submitted value.

See also:


Unrelated to the concrete problem. The @FacesConverter annotation on your converter is superflous. It is not been used in this construct. If you would have used it, the managed property would not have been injected at all. See also among others How can I inject in @FacesConverter?

Community
  • 1
  • 1
BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
  • BaluC thank you for your reply. My controller is view scoped so I am not sure what else it could be? Also I know the @FacesConveter is superfluous(only because I read one of your posts about it) however I was switching between #{fanlistConverter} and fanlistConverter in order to see what impact that had on injecting the dAL so I left it in. Any further help would be greatly appreciated. – sgoldberg Jan 23 '13 at 15:59
  • Okay, that brings us at the converter. Isn't it incorrectly returning `null` all the time while it should return a concrete `Fanlist`? A debugger/logger should give clues. – BalusC Jan 23 '13 at 16:26
  • BalusC the debug shows that the hibernate session set in the converter is null. For whatever reason when I call this from one component the session is not null, but when I call it from another component it is null. – sgoldberg Jan 23 '13 at 16:59
  • It's a Hibernate session? That's not the way how it's supposed to be used... You should open the session on a per-request(view) basis. It should absolutely not be assigned as a static variable. Are you using legacy Hibernate or Hibernate JPA? – BalusC Jan 23 '13 at 17:03
  • Yes it is Hibernate, and we are using JPA. We are new to Hibernate. We initially tried opening and closing sessions on a per request bases; however, we couldn't get lazy-loaded child lists using this method. I see what you are saying now though that we should have a session per view which would eliminate our lazy-load problem. I will investigate that, but I don't believe that is our issue as this works on another page. I appreciate the feedback though regardless as we are inexperienced at this. – sgoldberg Jan 23 '13 at 17:51