Eskir Eskir - 2 months ago 20
Java Question

Java - Vaadin - Table not filling

little bit of a pickle here. I am reading a JSON From a Zip file and I want to fill a table in Vaadin with the contents of the JSON.

Here's my Function to read the stuff and fill the table, this is Java.

private void getJsonContent() {
try {
FileInputStream fis = new FileInputStream(backupFile);
ZipInputStream zin = new ZipInputStream(new BufferedInputStream(fis));
ZipEntry entry;
byte[] buffer = new byte[1024];
while((entry = zin.getNextEntry()) != null) {
if(entry.getName().equalsIgnoreCase("content.json")) {
int n;
while((n = zin.read(buffer, 0, 1024)) > -1){
String JSON = new String(buffer, Charset.forName("UTF-8"));
JSONObject obj = new JSONObject(JSON);

logger.info(JSON);

// Assign "global" Values to Variables
this.createdAt = obj.getString("created_at");
this.version = obj.getString("version");

// Fill table if applicable
for(int i = 0; i < obj.getJSONArray("content").length(); i++) {
JSONObject sub = obj.getJSONArray("content").getJSONObject(i);
logger.info(sub);

infoTable.addItem(new Object[] {
sub.get("imported_identities").toString(),
sub.get("project_versions").toString(),
sub.get("last_import").toString(),
sub.get("client").toString(),
sub.get("project").toString()
}, i +1);
}
}
}
}
zin.close();
fis.close();
} catch (FileNotFoundException e) {
// Can't happen here
} catch (IOException e) {
logger.info("Can't read File.");
} catch (JSONException jse) {
logger.info("JSON Content could not be read: " + jse.getMessage());
}
}


You will notice I have a function call
logger.info(sub)
- to make sure what I get is another valid JSON Object (the file I am reading contains nested things)

Output:

{"imported_identities":0,"project_versions":0,"last_import":null,"client":"Client1","project":"Project2"}
{"imported_identities":0,"project_versions":0,"last_import":null,"client":"Client2","project":"Project1"}
{"imported_identities":0,"project_versions":1,"last_import":"2016-09-14T09:28:24.520Z","client":"Client1","project":"Project1"}


I made sure all the values were correct (and the table is built with null as default) - here is the table properties:

infoTable.addContainerProperty(impIds, String.class, null);
infoTable.addContainerProperty(projVe, String.class, null);
infoTable.addContainerProperty(lstImp, String.class, null);
infoTable.addContainerProperty(client, String.class, null);
infoTable.addContainerProperty(projct, String.class, null);

infoTable.setColumnCollapsingAllowed(true);
infoTable.setColumnCollapsed(impIds, true);
infoTable.setColumnCollapsed(projVe, true);
infoTable.setColumnCollapsed(lstImp, true);


Finally, the table has "refreshRowCache" called on it. Anyone see the problem? There are no errors, no nothing, the table just doesn't add the item (the size of
infoTable.getItemIds().size()
is 0 right after the call.

EDIT:

I tried the following to verify.

infoTable.addItem(i + 1);
infoTable.getItem(i + 1).getItemProperty(impIds).setValue(sub.get("imported_identities").toString());
infoTable.getItem(i + 1).getItemProperty(projVe).setValue(sub.get("project_versions").toString());


This went and caused a NullPointerException, the stack trace however does not contain any of my classes as far as I can see.

Answer

The following is wrong:

  1. The String constructor needs the read size (n).

                while ((n = zin.read(buffer, 0, 1024)) > -1) {
                    String JSON = new String(buffer, 0, n, StandardCharsets.UTF_8);
    
  2. Then you do JSONs of at most 1024 in the loop, instead on one JSON of it all

  3. The bytes of a UTF-8 cannot be split at some point say at position 1024 and expect to have a valid complete multi-byte sequence at end and following block's begin.

  4. Also there is readFully and closeEntry was missing.

In short:

private void getJsonContent() {
    try (ZipInputStream zin = new ZipInputStream(new BufferedInputStream(
            new FileInputStream(backupFile)))) {
        ZipEntry entry;
        while ((entry = zin.getNextEntry()) != null) {
            if (entry.getName().equalsIgnoreCase("content.json")) {
                long size = entry.getSize();
                if (size > 100_000) {
                    throw new IllegalArgumentException("Data too large");
                }
                // We could use an InputStreamReader and read text piecewise.
                // However JSON parsing also is easiest on an entire text.
                byte[] buffer = new byte[(int)size];
                int n = zin.readFully(buffer, 0, buffer.length);
                String json = new String(buffer, StandardCharsets.UTF_8);
                JSONObject obj = new JSONObject(json);
                logger.info(json);

                // Assign "global" Values to Variables
                this.createdAt = obj.getString("created_at");
                this.version = obj.getString("version");

                // Fill table if applicable                     
                for (int i = 0; i < obj.getJSONArray("content").length(); i++) {
                    JSONObject sub = obj.getJSONArray("content").getJSONObject(i);
                    logger.info(sub);

                    infoTable.addItem(new Object[] {
                            sub.get("imported_identities").toString(),
                            sub.get("project_versions").toString(),
                            sub.get("last_import").toString(),
                            sub.get("client").toString(),
                            sub.get("project").toString()
                    }, i + 1);
                }
            } // if
            zin.closeEntry(); // Do not forget preparing for the next entry
        }
    } catch (IOException e) {
        logger.info("Can't read File.");
    } catch (JSONException jse) {
        logger.info("JSON Content could not be read: " + jse.getMessage());
    }
}

The try-with-resources closes automatically even on exception or return.