0

I am running into a common issue with JSP not displaying data. However, I am following documentation and have also tried the solutions to the many questions that have been asked on this site without any success.

How can I display java.io.File data in JSP? If I am doing so correctly, is there any additional configuration required?

I have a File[] using java.io.File which is created in a javax.servlet.http.HttpServlet. I then take the File[] and add it as an attribute to my HttpSession. This is then forwarded to the JSP file, passed to a forEach tag, and populated into a table. (see this article)

This is my java servlet:

public class LogManagement extends HttpServlet {

    private static final Logger logger = LoggerFactory.getLogger(LogManagement.class);

    
    private static final String BASE_DIRECTORY = System.getProperty("catalina.base");
    private static final File CURRENT_LOGS_FOLDER = new File(BASE_DIRECTORY + "/logs");
    private static final File CAPTURED_LOGS_FOLDER = new File(BASE_DIRECTORY + "/logs/captured");

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        logger.info("GET called on LogManagement servlet");
        try {
            getLogs(request);
            getServletContext().getRequestDispatcher("/LogManagement.jsp").forward(request, response);
        } catch (Exception e) {
            logger.info("ERROR unable to GET log data");
            logger.info(e.getMessage());
        }
    }

    private void getLogs(HttpServletRequest request) {
        logger.info("Getting logs");
        File[] currentLogs = CURRENT_LOGS_FOLDER.listFiles();
        File[] capturedLogs = CAPTURED_LOGS_FOLDER.listFiles();

        HttpSession session = request.getSession();
        session.setAttribute("currentLogs", currentLogs);
        session.setAttribute("capturedLogs", capturedLogs);
        logger.info("Got logs");
    }
}

This is my jsp for two of the solutions I tried from here and here (yes I know it uses some deprecated tag attributes, but I am unable to change those)

Solution 1:

        <table style="margin-top: 5px; width: 600px;" align="left">
            <tr>
                <td align="left">
                    Current Logs:
                </td>
            </tr>
            <tr>
                <td>
                    <div class="file-viewer">
                        <table>
                            <c:forEach var="file" items="${currentLogs}">
                                <tr>
                                    <td><c:out value="${file.name}"/></td>
                                    <td><c:out value="${file.length}"/></td>
                                    <td><c:out value="${file.lastModified}"/></td>
                                </tr>
                            </c:forEach>
                        </table>
                    </div>
                </td>
            </tr>
        </table>

Solution 2:

        <table style="margin-top: 5px; width: 600px;" align="left">
            <tr>
                <td align="left">
                    Captured Logs:
                </td>
            </tr>
            <tr>
                <td>
                    <div class="file-viewer">
                        <table>
                            <c:forEach var="file" items="${capturedLogs}">
                                <tr>
                                    <td>${file.name}</td>
                                    <td>${file.length}</td>
                                    <td>${file.lastModified}</td>
                                </tr>
                            </c:forEach>
                        </table>
                    </div>
                </td>
            </tr>
        </table>

These are the two solutions I have seen in documentation and in various SO answers. I have also tried <% out.print(file.getName()); %> inside of the td tag with no luck (see unable to display jsp data in table)

This is the exception that I get:

An exception occurred processing [/LogManagement.jsp] at line [51]__48: ________c:forEach var=file items=${currentLogs}49: _____tr__50: ___________td__c:out value=${file.name}//td__51: ___________td__c:out value=${file.length}//td__52: _________td__c:out value=${file.lastModified}//td__53: __________/tr__54: _________/c:forEach____Stacktrace:

If I replace the data I am looking for with dummy data, I get a print out for each item.

<td>fileName</td>
<td>fileSize</td>
<td>lastEdited</td>

gives a table with rows equal to the number of files I am looking at showing:

"fileName fileSize lastEdited"

This shows that my forEach is working, but that the references to the specific data are not.

Logan Kitchen
  • 744
  • 3
  • 13
  • 26

2 Answers2

0

Looks like you're missing the c:out tag, like the one you inserted above when looping over currentLogs.

As a side note, unless it's a requirement for a university course or a legacy project, it's really not worth it to learn JSP in 2021.

  • I'm sorry, I meant to have those two sections of jsp separate. I tried both solutions (with and without c:out) and neither worked. I made an edit to clarify. Yeah, I tried getting permission to update this to a newer and easier to use technology, but no go. Unfortunately, I need to support the legacy product. At least it isn't a Perl application, which some of my teammates have had to work with. – Logan Kitchen Jul 09 '21 at 00:22
0

The issue is that JSTL expects to find getter functions when searching for a property of an object. Specifically it means that there is some method with "get" as the first three characters of the method name.

In the example <td>${file.name}</td> would work on its own since java.io.File has a method called "getName()". However, both length and lastModified do not have "get" as a prefix (.length() and .lastModified()) eventhough they simply retrieve a value.

There are many ways to solve this (extending the object, adding "get" methods, etc) but I think the simplest is using a class for a new object.

I added a class to the end of the above .java file and used that instead of java.io.File objects. It works just fine:

The New Class:

public class LogFile {
    private String name;
    private long length;
    private String lastModified;

    public LogFile(File file) {
        this.name = file.getName();
        this.length = file.length() / 1024;
        this.lastModified = timeStampFormat.format(file.lastModified());
    }

    public String getName() {
        return this.name;
    }

    public long getLength() {
        return this.length;
    }

    public String getLastModified() {
        return this.lastModified;
    }
}

Using the Objects:

    File[] currentLogFiles = CURRENT_LOGS_FOLDER.listFiles();
    File[] capturedLogFiles = CAPTURED_LOGS_FOLDER.listFiles();
    List<LogFile> currentLogs = new ArrayList<>();
    List<LogFile> capturedLogs = new ArrayList<>();

    if (currentLogFiles != null) {
        for (File file : currentLogFiles) {
            currentLogs.add(new LogFile(file));
        }
    }
    if (capturedLogFiles != null) {
        for (File file : capturedLogFiles) {
            currentLogs.add(new LogFile(file));
        }
    }

    HttpSession session = request.getSession();
    session.setAttribute("currentLogs", currentLogs);
    session.setAttribute("capturedLogs", capturedLogs);

as a side note: both ${file.name} and <c:out value="${file.name}" /> work in jst as far as I have found.

Logan Kitchen
  • 744
  • 3
  • 13
  • 26