4

I getting a Conversion Error when try delete or edit a user from a table in my application. The value is being passed in the metadata from the listUser.xhmtl to the deleteUser.xhtml page. The value is being passed in the metadata but for some reason upon calling the delete action I get the Conversion Error setting value "someemail@somedomain.com" for 'null Converter'. The user id is a String.

This is the url after requesting the userDelete.xhmtl:

http://localhost:8080/lavpWebApp/user/deleteUser.xhtml?user=someemail%40somedomain.com

This is the userList.xhmtl simplified:

<h:column>
                            <f:facet name="header">Edit</f:facet>
                            <h:link outcome="/user/editUser.xhtml" value="Edit User">
                                <f:param name="user" value="#{item.email}"/>
                            </h:link>                            
                        </h:column>

                        <h:column>
                            <f:facet name="header">Delete</f:facet>
                            <h:link outcome="/user/deleteUser.xhtml" value="Delete User">
                                <f:param name="user" value="#{item.email}"/>
                            </h:link>
                        </h:column>

This is userDelete.xhtml simplified:

<f:metadata>
        <f:viewParam name="user" value="#{userController.user}" converter="#{userConverter}"/>
    </f:metadata>

    <h:body>
        Do you want to delete #{userController.user.name}?
        <h:form>
            <h:commandButton action="#{userController.deleteUser()}"
                             value="Delete"/>
            <h:commandButton action="#{userController.doCancelDeleteUser()}"
                             value ="Cancel"/>
        </h:form>
    </h:body>

This is the Converter class:

@ManagedBean
@FacesConverter(value="userConverter")
public class UserConverter implements Converter{

    @EJB
    private UserSellerEJB userEjb;

    @Override
    public Object getAsObject(FacesContext context, UIComponent component, String value) {
        if (value == null || value.isEmpty())
        {
            return null;
        }
        if(!value.matches("\\d+"))
        {
            throw new ConverterException("The value is not a valid email: " + value);
        }

        String id = value.toString();
        return userEjb.findUserById(id);

    }

    @Override
    public String getAsString(FacesContext context, UIComponent component, Object value) {
        if(value == null)
        {
            return null;
        }

        if(!(value instanceof UserSeller))
        {
            throw new ConverterException("The value is not a User: " + value);            
        }

        String id = ((UserSeller) value).getEmail();
        return (id != null) ? id.toString() : null;
    }

}

This is the userController class simplified:

@Named
@RequestScoped
public class UserController{

    @EJB
    private UserSellerEJB userEJB;

    private UserSeller user = new UserSeller(); 
    private List<UserSeller> usersList = new ArrayList<UserSeller>();

    // ------------------------------------------------------------- Constructor
    public UserController() {
    }

    // -------------------------------------------------------- Business Methods

    public String doCreateUser()
    {
        user = userEJB.createSeller(user);
        usersList = userEJB.findAllSellers();
        return "listUser?faces-redirect=true";        
    }

        // update user

        public void PreRenderView()
        {
            if(user == null)
            {
                user = new UserSeller();
            }            
        }

        public String doUpdateUser()
        {
            if(user.getEmail() != null)
            {
                userEJB.updateSeller(user);
            }
            else
            {
                userEJB.createSeller(user);
            }

            return "listUser?faces-redirect=true";
        }

    public String deleteUser()
    {
        userEJB.deleteSeller(user);
        return "listUser?faces-redirect=true";
    }

    public String doCancelDeleteUser()
    {
        return "listUser?faces-redirect=true";
    }


    @PostConstruct
    public void init()
    {
        usersList = userEJB.findAllSellers();       
    }
lv10
  • 1,469
  • 7
  • 25
  • 46
  • try assigning a `name` to the `@ManagedBean` annotation and using that instead to access the converter. Make sure it's different from the one you're already using in the `@FacesConverter` – kolossus Nov 11 '12 at 21:31
  • A `@ManagedBean` can't have the `@FacesConverter` annotation. Remove the `@ManagedBean` annotation ant the code will work. By the way, you're mixing JSF with CDI, it will be better to study both and their differences. Related: [Inject a EJB into a JSF converter with JEE6](http://stackoverflow.com/q/2019495/1065197). – Luiggi Mendoza Nov 12 '12 at 00:59
  • @kolossus thanks. I have added the `name` to the `@ManagedBean`, I used `@ManagedBean(name="userSellerConverter")` but still it's giving the same error. – lv10 Nov 12 '12 at 01:04
  • @LuiggiMendoza, that's not accurate. A converter can also be annotated with `@ManagedBean`. I know because I've done it several times. It's the only way the converter can have access to `@Inject` type resources – kolossus Nov 12 '12 at 01:07
  • @kolossus check the link in my comment. – Luiggi Mendoza Nov 12 '12 at 01:25
  • @LuiggiMendoza, saw the winning answer. Also saw http://stackoverflow.com/a/8919591/1530938. I'm not saying it's pretty or correct, but it can be done – kolossus Nov 12 '12 at 01:58
  • @kolossus and @LuiggiMendoza I have tried both methods both are not working. I have used @Kolossus approach before and it worked, but this time it is not working. I have tried different methods, I have even tried "@Inject" and using `@FacesConverter("ForClass= UserController.class")` I really don't know where the problem is. Is there any other suggestions, you guys may have. – lv10 Nov 12 '12 at 02:51
  • @kolossus after using your suggestion and restarting the server. I got this error instead `{0}: Conversion error occurred.` Thanks in advance. – lv10 Nov 12 '12 at 02:52
  • @lv10, from everything you've put here, this may just be your app server/ide screwing with you(eclipse can be a b****). I'd suggest you move on with an alternative path to setting up that object like [this](http://stackoverflow.com/a/13332562/1530938) so you don't spend too much time on this one method – kolossus Nov 12 '12 at 06:03
  • 1
    Technically, Luiggi is right that a `@ManagedBean` cannot have a `@FacesConverter` annotation. It's usually the one or the other, not both. – BalusC Nov 12 '12 at 11:46
  • @LuiggiMendoza thank you very much. I now better understand how custom converters work. @BalusC answer solved the problem, I just removed faces annotation and changed to `@Named`. It works now beautifully. – lv10 Nov 13 '12 at 02:10

1 Answers1

5

The null converter in the exception message indicates that the converter instance cannot be found. Since you're referencing the converter as a managed bean by converter="#{userConverter}, it would only be found if it's annotated with @javax.faces.bean.ManagedBean and if the class is located in the WAR (and thus not in the EJB/EAR or elsewhere!).

The @FacesConverter annotation isn't been used in this construct and in fact superfluous — and only confusing to starters. Remove that annotation. The @EJB works indeed only in managed beans.

If really in vain (I could however not explain why), try managing it by CDI instead: replace the JSF @ManagedBean annotation by the CDI @Named annotation. You're apparently already successfully managing front controller beans by CDI.


Unrelated to the concrete problem, the converter seems to be designed to convert based on a technical ID (a DB primary key), not an email address. An email address can never match \d+ (which is regex for "digits only"). Make sure that you're not confusing email address with ID.

BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
  • thank you very much for your detailed suggestions. I have followed your instructions, I removed the `@FacesConverter` annotation, I have also replaced the `@ManagedBean` annotation for `@Named("userConverter")`. I have also removed the regex condition. I'm using the email as an id for this `User` that is why I used email. Problem is now fixed. Thank you very much. – lv10 Nov 13 '12 at 02:05
  • BalusC - onie question: I am new to JSF and have read that @FacesConverter is required and would like to fully understand why I needed to remove it in this case. Could you extend a little bit your explanation on why we removed it for this converter? - Thanks in advance. – lv10 Nov 13 '12 at 02:09
  • 1
    That's because you want to inject an `@EJB` in it. The `@FacesConverter` (and `@FacesValidator`) is however not a supported injection target. This oversight is fixed in upcoming JSF 2.2. – BalusC Nov 13 '12 at 10:52
  • Thank you very much, I got it now. – lv10 Nov 13 '12 at 16:27