JSF 2.2: File upload with h:inputFile

After so many years it finally happened! The JSF 2.2 specification features a file upload component. In this post of the series on JSF 2.2 I will show how to upload files with the brand new h:inputFile component.

As JSF 2.2 requires Servlet 3.0 it is finally possible to have the file upload component h:inputFile in the standard. h:inputFile is basically used like any other JSF input component. The upload is stored in a bean property of type javax.servlet.http.Part referenced in the value attribute. As a prerequisite, the form submit encoding must be set to multipart/form-data in the enctype attribute of the enclosing h:form.

The following listing shows a form with a file upload component and a command button referencing an action method which processes the uploaded file.

<h:form id="form" enctype="multipart/form-data">
  <h:inputFile id="file" value="#{bean.file}"/>
  <h:commandButton value="Upload"
      action="#{bean.upload}"/>
</h:form>

The next listing shows the bean used in the view above. In the action method upload() the content of the file is read from the provided input stream and stored in the String fileContent.

public class Bean {
  private Part file;
  private String fileContent;

  public void upload() {
    try {
      fileContent = new Scanner(file.getInputStream())
          .useDelimiter("\\A").next();
    } catch (IOException e) {
      // Error handling
    }
  }

  public Part getFile() {
    return file;
  }

  public void setFile(Part file) {
    this.file = file;
  }
}

As h:inputFile is a JSF input component, it can have a converter and validators. Let’s add a validator to the component that checks the size and mime type of the uploaded file. The validation is done in the validator method validateFile in the managed bean. This method is referenced in the validator attribute of h:inputFile like this:

<h:inputFile id="file" value="#{bean.file}"
    validator="#{bean.validateFile}"/>

The following listing shows the validator method itself. You will see that there is nothing fancy about it. The validation works just like it would for any other input component. As mentioned before, the uploaded file is stored in an instance of class javax.servlet.http.Part. Therefore we can assume this class for the object passed into the validator which allows us to check the size and content type.

public void validateFile(FacesContext ctx,
                         UIComponent comp,
                         Object value) {
  List<FacesMessage> msgs = new ArrayList<FacesMessage>();
  Part file = (Part)value;
  if (file.getSize() > 1024) {
    msgs.add(new FacesMessage("file too big"));
  }
  if (!"text/plain".equals(file.getContentType())) {
    msgs.add(new FacesMessage("not a text file"));
  }
  if (!msgs.isEmpty()) {
    throw new ValidatorException(msgs);
  }
}

JSF also specifies uploading files via Ajax. h:inputFile can be combined with f:ajax like any other JSF input component. In the following listing the file upload is initiated via an ajaxified h:commandButton. But it would also be possible to add f:ajax directly to h:inputFile. In this case the ajax request would be started with the (pseudo) event valueChange.

<h:form id="form" enctype="multipart/form-data">
  <h:inputFile id="file" value="#{bean.file}"
      validator="#{bean.validateFile}"/>
  <h:commandButton value="Upload"
      action="#{bean.upload}">
    <f:ajax execute="file" render="@all"/>
  </h:commandButton>
  <h:inputTextarea value="#{bean.fileContent}"
      readonly="true"/>
</h:form>

Normally, render would contain the IDs of components to re-render. Unfortunately, Mojarra currently has a bug that forces the use of @all for ajax requests with file uploads (see JAVASERVERFACES-2851 for details).

The source code for the JSF 2.2 series examples can be found in the JSFlive Github repository jsf22-examples (module jsf22-input-file).

Further official details about JSF 2.2 can be found in the JSR 344: JavaServer Faces 2.2.

Advertisements

27 responses to “JSF 2.2: File upload with h:inputFile

  1. Pingback: What's new in JSF 2.2? | J-Development

  2. kathleen macapaz

    where can i download JSF 2.2??

    • Neither MyFaces nor Mojarra have released an official 2.2 version so far. You can have a look at my examples at Github to see how the milestone release of Mojarra or the snapshot release of MyFaces can be used in Maven based projects. You have to be aware that the current versions are not production ready yet.

  3. Hi, I’ve been watching this blog a few weeks ago. Good blog.
    I have a problem when validating a file, I’m using tomcat 7.0.40. Validation works fine, but when I want to submit again I’m getting the exception

    java.lang.IllegalStateException: java.lang.InstantiationException: org.apache.catalina.core.ApplicationPart
    at javax.faces.component.StateHolderSaver.restore(StateHolderSaver.java:153)
    at javax.faces.component.ComponentStateHelper.restoreState(ComponentStateHelper.java:306)
    at javax.faces.component.UIComponentBase.restoreState(UIComponentBase.java:1577)

    Have you ever faced this issue?

    Thanks

  4. Figure it out. I was using a not released version of the JSF (http://mvnrepository.com/artifact/com.sun.faces/jsf-api/2.2.0-m03). Now im using 2.2.0 release

    Sorry to post the question here, I was getting a little desperate
    Regards

  5. Since JSF 2.2 is released already. Is it possible to upload multiple files with JSF 2.2 now? It would be funny if JSF finally added standardized upload file mechanism after so many years, but lacking such a feature. Still chasing the past.
    Thanks for reply.

    • I don’t think uploading multiple files with one h:inputFile component is currently supported. I think this would mean rendering HTML5, which is not done yet. But you get this feature with PrimeFaces for example.

  6. Hi, just wondering if JSF2.2 is available now? If so, is there any tutorial for creating JSF2.2 project in Eclipse Juno?
    Thanks in advance for your help.

    • Yes, Mojarra 2.2.1 is available. I am not aware of special tutorials for JSF 2.2 with Eclipse but there is not so much difference to older versions, especially 2.1 or 2.0.
      But I would recommend to use Maven anyway – then you can use of one my GitHub examples as a template.

  7. Hi all!

    I cannot deploy this project on GlassFish
    I have made a war file and when deploying I get an error:

    java.util.concurrent.ExecutionException: com.sun.faces.config.ConfigurationException: Unable to parse document ‘jndi:/server/jsf22-input-file/WEB-INF/faces-config.xml’: null.

    Does anybody have an idea how to fix it?

    Many thanks!

    Alex

  8. To the GlassFish server is not working
    Can you help me?

  9. Interesting article! Thank you!
    I have a question. h:inputFile component works good in the Mojarra 2.2.
    I switched to the MyFaces (bundle 2.2 ) latest 28 November snap. and h:inputFile does not work.
    It cannot do “#{bean.upload}” and doesn’t show any errors.
    Problems with the MyFaces?

  10. Hi,
    No! I have created project from scratch and copy-pasted UploadPage.java,index.html,upload.xhtml and web.xml from your project (jsf22-input-file)
    I am using Eclipse, Tomcat 7, Java 7 and MyFaces 2.2
    I used list of libraries all related to Myfaces and fileupload libs:
    commons-beanutils-1.8.3.jar
    commons-codec-1.3.jar
    commons-collections-3.2.jar
    commons-digester-1.8.jar
    commons-el-1.0.jar
    commons-fileupload-1.3.jar
    commons-io-2.4.jar
    commons-logging-1.1.1.jar
    geronimo-atinject_1.0_spec-1.0.jar
    geronimo-jcdi_1.0_spec-1.0.jar
    myfaces-api-2.2.0-20131128.134302-2566.jar
    myfaces-bundle-2.2.0-20131128.135353-2554.jar
    myfaces-impl-2.2.0-20131128.135141-2554.jar

    Clicking button doesn’t do anything even call upload or validate method.
    In Mojarra it worked.
    Is it weird? May be I should use additional libraries or add some parameters in the web.xml?
    Thanks,

  11. You probably need a in the web.xml for the faces servlet.

  12. Pingback: tomawak | mauroprogram's Blog

  13. Hi , you made my day , thank you so much , please , i wonder if it possible to display the file like ” h:graphicImage “.
    Is the file that is uploaded , is stored somewhere ?
    Thank you to replay 🙂

  14. please you can explain me the use of fileContent = new Scanner(file.getInputStream())
    .useDelimiter(“\\A”).next();
    from the method upload() ?????

    what it is the method useDelimeter(“\\A”|),next of class Scanner?

    public void upload() {
    try {
    fileContent = new Scanner(file.getInputStream())
    .useDelimiter(“\\A”).next();
    } catch (IOException e) {
    // Error handling
    }
    }

  15. Hi there,

    i am using apache tomcat 7, myFaces and JSF 2.2
    implementing like stated above will throw a null pointer exception after selecting the file. so whats wrong here? do i need an initiale somehwere

  16. Hello.
    Using Majorra 2.2 and Tomcat 7. Even the setter of my variable used in the f:input tag is executed. The getter method is?
    enctype type is correct. A primefaces fileupload within the same form is working, but I wont use primefaces…
    Any suggestions?

  17. sorry. is not executed. getter is working, setter is not working.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s