From 6fed3ee38481764ac713229fa08e8a34a15204ca Mon Sep 17 00:00:00 2001 From: Pascal Gelinas Date: Wed, 12 Dec 2012 08:29:16 -0500 Subject: [PATCH 1/3] Don't provide an initial capacity to the array list by using total_rows, since it indicates the total row in a view, not the result. --- .../src/main/java/org/ektorp/impl/QueryResultParser.java | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/org.ektorp/src/main/java/org/ektorp/impl/QueryResultParser.java b/org.ektorp/src/main/java/org/ektorp/impl/QueryResultParser.java index adbdc3ac..d070a99a 100644 --- a/org.ektorp/src/main/java/org/ektorp/impl/QueryResultParser.java +++ b/org.ektorp/src/main/java/org/ektorp/impl/QueryResultParser.java @@ -67,11 +67,7 @@ public void parseResult(InputStream json) throws IOException { } else if(TOTAL_ROWS_FIELD_NAME.equals(currentName)){ totalRows = jp.getIntValue(); } else if (ROWS_FIELD_NAME.equals(currentName)){ - if(totalRows == -1){ - rows = new ArrayList(); - }else{ - rows = new ArrayList(totalRows); - } + rows = new ArrayList(); parseRows(jp); }else{ // Handle cloudant errors. From 09f2a0bf9442e6d2b19b02e0c326de0f1971427e Mon Sep 17 00:00:00 2001 From: Pascal Gelinas Date: Wed, 12 Dec 2012 08:41:27 -0500 Subject: [PATCH 2/3] Ensure parser is closed at the end. --- .../java/org/ektorp/impl/QueryResultParser.java | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/org.ektorp/src/main/java/org/ektorp/impl/QueryResultParser.java b/org.ektorp/src/main/java/org/ektorp/impl/QueryResultParser.java index d070a99a..593bc133 100644 --- a/org.ektorp/src/main/java/org/ektorp/impl/QueryResultParser.java +++ b/org.ektorp/src/main/java/org/ektorp/impl/QueryResultParser.java @@ -52,9 +52,17 @@ public QueryResultParser(Class type, ObjectMapper mapper) { } public void parseResult(InputStream json) throws IOException { - JsonParser jp = mapper.getFactory().createJsonParser(json); + JsonParser jp = mapper.getFactory().createParser(json); - if (jp.nextToken() != JsonToken.START_OBJECT) { + try { + parseResult(jp); + } finally { + jp.close(); + } + } + + private void parseResult(JsonParser jp) throws IOException { + if (jp.nextToken() != JsonToken.START_OBJECT) { throw new DbAccessException("Expected data to start with an Object"); } @@ -79,7 +87,7 @@ public void parseResult(InputStream json) throws IOException { JsonNode error = mapper.convertValue(errorFields, JsonNode.class); throw new DbAccessException(error.toString()); } - } + } private void parseRows(JsonParser jp) throws IOException{ if (jp.getCurrentToken() != JsonToken.START_ARRAY) { From c90aa04a1b90b1063121ba612ba02f6d80cd4032 Mon Sep 17 00:00:00 2001 From: Pascal Gelinas Date: Wed, 12 Dec 2012 08:41:38 -0500 Subject: [PATCH 3/3] Formatted. --- .../org/ektorp/impl/QueryResultParser.java | 244 +++++++++--------- 1 file changed, 125 insertions(+), 119 deletions(-) diff --git a/org.ektorp/src/main/java/org/ektorp/impl/QueryResultParser.java b/org.ektorp/src/main/java/org/ektorp/impl/QueryResultParser.java index 593bc133..aa3fbcc4 100644 --- a/org.ektorp/src/main/java/org/ektorp/impl/QueryResultParser.java +++ b/org.ektorp/src/main/java/org/ektorp/impl/QueryResultParser.java @@ -22,36 +22,36 @@ * @author Pascal GĂ©linas (rewrite for issue #98) */ public class QueryResultParser { - private static final String NOT_FOUND_ERROR = "not_found"; + private static final String NOT_FOUND_ERROR = "not_found"; private static final String ROWS_FIELD_NAME = "rows"; - private static final String VALUE_FIELD_NAME = "value"; - private static final String ID_FIELD_NAME = "id"; - private static final String ERROR_FIELD_NAME = "error"; - private static final String KEY_FIELD_NAME = "key"; - private static final String INCLUDED_DOC_FIELD_NAME = "doc"; - private static final String TOTAL_ROWS_FIELD_NAME = "total_rows"; - private static final String OFFSET_FIELD_NAME = "offset"; - - private int totalRows = -1; - private int offset = -1; - private List rows; - - private String firstId; - private JsonNode firstKey; - - private String lastId; - private JsonNode lastKey; - - private final ObjectMapper mapper; - private final Class type; - private boolean ignoreNotFound; - - public QueryResultParser(Class type, ObjectMapper mapper) { - this.type = type; - this.mapper = mapper; - } - - public void parseResult(InputStream json) throws IOException { + private static final String VALUE_FIELD_NAME = "value"; + private static final String ID_FIELD_NAME = "id"; + private static final String ERROR_FIELD_NAME = "error"; + private static final String KEY_FIELD_NAME = "key"; + private static final String INCLUDED_DOC_FIELD_NAME = "doc"; + private static final String TOTAL_ROWS_FIELD_NAME = "total_rows"; + private static final String OFFSET_FIELD_NAME = "offset"; + + private int totalRows = -1; + private int offset = -1; + private List rows; + + private String firstId; + private JsonNode firstKey; + + private String lastId; + private JsonNode lastKey; + + private final ObjectMapper mapper; + private final Class type; + private boolean ignoreNotFound; + + public QueryResultParser(Class type, ObjectMapper mapper) { + this.type = type; + this.mapper = mapper; + } + + public void parseResult(InputStream json) throws IOException { JsonParser jp = mapper.getFactory().createParser(json); try { @@ -59,51 +59,52 @@ public void parseResult(InputStream json) throws IOException { } finally { jp.close(); } - } + } private void parseResult(JsonParser jp) throws IOException { if (jp.nextToken() != JsonToken.START_OBJECT) { - throw new DbAccessException("Expected data to start with an Object"); - } - - Map errorFields = new HashMap(); - // Issue #98: Can't assume order of JSON fields. - while(jp.nextValue() != JsonToken.END_OBJECT){ - String currentName = jp.getCurrentName(); - if(OFFSET_FIELD_NAME.equals(currentName)){ - offset = jp.getIntValue(); - } else if(TOTAL_ROWS_FIELD_NAME.equals(currentName)){ - totalRows = jp.getIntValue(); - } else if (ROWS_FIELD_NAME.equals(currentName)){ + throw new DbAccessException("Expected data to start with an Object"); + } + + Map errorFields = new HashMap(); + // Issue #98: Can't assume order of JSON fields. + while (jp.nextValue() != JsonToken.END_OBJECT) { + String currentName = jp.getCurrentName(); + if (OFFSET_FIELD_NAME.equals(currentName)) { + offset = jp.getIntValue(); + } else if (TOTAL_ROWS_FIELD_NAME.equals(currentName)) { + totalRows = jp.getIntValue(); + } else if (ROWS_FIELD_NAME.equals(currentName)) { rows = new ArrayList(); - parseRows(jp); - }else{ - // Handle cloudant errors. - errorFields.put(jp.getCurrentName(), jp.getText()); - } - } - - if(!errorFields.isEmpty()){ - JsonNode error = mapper.convertValue(errorFields, JsonNode.class); + parseRows(jp); + } else { + // Handle cloudant errors. + errorFields.put(jp.getCurrentName(), jp.getText()); + } + } + + if (!errorFields.isEmpty()) { + JsonNode error = mapper.convertValue(errorFields, JsonNode.class); throw new DbAccessException(error.toString()); - } + } } - private void parseRows(JsonParser jp) throws IOException{ - if (jp.getCurrentToken() != JsonToken.START_ARRAY) { + private void parseRows(JsonParser jp) throws IOException { + if (jp.getCurrentToken() != JsonToken.START_ARRAY) { throw new DbAccessException("Expected rows to start with an Array"); } - - // Parses the first row that isn't an error row to find out which field to use (doc or value). - String dataField = null; - while (dataField == null && jp.nextToken() == JsonToken.START_OBJECT) { + + // Parses the first row that isn't an error row to find out which field + // to use (doc or value). + String dataField = null; + while (dataField == null && jp.nextToken() == JsonToken.START_OBJECT) { Row row = jp.readValueAs(Row.class); if (row.error != null) { - if (!ignoreError(row.error)){ + if (!ignoreError(row.error)) { throw new ViewResultException(row.key, row.error); } continue; - } + } if (row.doc != null) { dataField = INCLUDED_DOC_FIELD_NAME; rows.add(mapper.readValue(row.doc.traverse(), type)); @@ -114,86 +115,91 @@ private void parseRows(JsonParser jp) throws IOException{ firstId = row.id; firstKey = row.key; } - // After the while, either we point at END_ARRAY but we have no dataField (all rows were error), - // or we point at an END_OBJECT (end of a row) and have determined which data field to use. - if(dataField == null) return; - - // Parse all the remaining rows; jp points at START_OBJECT except after the last row - while(jp.nextToken() != JsonToken.END_ARRAY){ - String currentId = null; - JsonNode currentKey = null; + // After the while, either we point at END_ARRAY but we have no + // dataField (all rows were error), + // or we point at an END_OBJECT (end of a row) and have determined which + // data field to use. + if (dataField == null) + return; + + // Parse all the remaining rows; jp points at START_OBJECT except after + // the last row + while (jp.nextToken() != JsonToken.END_ARRAY) { + String currentId = null; + JsonNode currentKey = null; String error = null; - T value = null; - // Parse the fields of a row; jp points at a value token except after the last field. - while(jp.nextValue() != JsonToken.END_OBJECT){ - String currentName = jp.getCurrentName(); - if(ID_FIELD_NAME.equals(currentName)){ - currentId = jp.getText(); - } else if (KEY_FIELD_NAME.equals(currentName)){ - currentKey = jp.readValueAsTree(); - } else if(dataField.equals(currentName)){ - value = jp.readValueAs(type); - } else if(ERROR_FIELD_NAME.equals(currentName)){ + T value = null; + // Parse the fields of a row; jp points at a value token except + // after the last field. + while (jp.nextValue() != JsonToken.END_OBJECT) { + String currentName = jp.getCurrentName(); + if (ID_FIELD_NAME.equals(currentName)) { + currentId = jp.getText(); + } else if (KEY_FIELD_NAME.equals(currentName)) { + currentKey = jp.readValueAsTree(); + } else if (dataField.equals(currentName)) { + value = jp.readValueAs(type); + } else if (ERROR_FIELD_NAME.equals(currentName)) { error = jp.getText(); } else { // Skip fields value that are of no interest to us. jp.skipChildren(); } - } - if (error != null && !ignoreError(error)){ + } + if (error != null && !ignoreError(error)) { throw new ViewResultException(currentKey, error); - } - // If the current row is an error row, then value will be null - if(value != null){ - lastId = currentId; - lastKey = currentKey; - rows.add(value); - } - } - } + } + // If the current row is an error row, then value will be null + if (value != null) { + lastId = currentId; + lastKey = currentKey; + rows.add(value); + } + } + } private boolean ignoreError(String error) { return ignoreNotFound && NOT_FOUND_ERROR.equals(error); } - public int getTotalRows() { - return totalRows; - } + public int getTotalRows() { + return totalRows; + } - public int getOffset() { - return offset; - } + public int getOffset() { + return offset; + } + + public List getRows() { + return rows; + } - public List getRows() { - return rows; - } - - public String getLastId() { + public String getLastId() { return lastId; } - - public JsonNode getLastKey() { + + public JsonNode getLastKey() { return lastKey; } - - public String getFirstId() { + + public String getFirstId() { return firstId; } - - public JsonNode getFirstKey() { + + public JsonNode getFirstKey() { return firstKey; } - public void setIgnoreNotFound(boolean ignoreNotFound) { - this.ignoreNotFound = ignoreNotFound; - } - - @JsonAutoDetect(fieldVisibility=Visibility.ANY) - private static class Row { - private String id; - private JsonNode key; - private JsonNode value; - private JsonNode doc; - private String error; - } + public void setIgnoreNotFound(boolean ignoreNotFound) { + this.ignoreNotFound = ignoreNotFound; + } + + @JsonAutoDetect(fieldVisibility = Visibility.ANY) + private static class Row { + private String id; + private JsonNode key; + private JsonNode value; + private JsonNode doc; + private String error; + } }