diff --git a/jOOQ/src/main/java/org/jooq/JSONFormat.java b/jOOQ/src/main/java/org/jooq/JSONFormat.java index 80d28ee307..2911d59754 100644 --- a/jOOQ/src/main/java/org/jooq/JSONFormat.java +++ b/jOOQ/src/main/java/org/jooq/JSONFormat.java @@ -60,8 +60,11 @@ package org.jooq; */ public final class JSONFormat { - final boolean header; - final RecordFormat recordFormat; + public static final JSONFormat DEFAULT_FOR_RESULTS = new JSONFormat(); + public static final JSONFormat DEFAULT_FOR_RECORDS = new JSONFormat().header(false); + + final boolean header; + final RecordFormat recordFormat; public JSONFormat() { this( diff --git a/jOOQ/src/main/java/org/jooq/Record.java b/jOOQ/src/main/java/org/jooq/Record.java index 2c47df5397..70fef05bcd 100644 --- a/jOOQ/src/main/java/org/jooq/Record.java +++ b/jOOQ/src/main/java/org/jooq/Record.java @@ -1313,6 +1313,54 @@ public interface Record extends Attachable, Comparable { // Formatting methods // ------------------------------------------------------------------------- + /** + * Get a simple formatted representation of this result as a JSON array. + *

+ * The format is the following:

+     * [value-2-1,value-2-2,...,value-2-n]
+     * 
+ * + * @return The formatted result + */ + String formatJSON(); + + /** + * Get a simple formatted representation of this result as a JSON data + * structure, according to the format. + * + * @return The formatted result + * @see JSONFormat + */ + String formatJSON(JSONFormat format); + + /** + * Like {@link #formatJSON()}, but the data is output onto an {@link OutputStream}. + * + * @throws IOException - an unchecked wrapper for {@link java.io.IOException}, if anything goes wrong. + */ + void formatJSON(OutputStream stream) throws IOException; + + /** + * Like {@link #formatJSON(JSONFormat)}, but the data is output onto an {@link OutputStream}. + * + * @throws IOException - an unchecked wrapper for {@link java.io.IOException}, if anything goes wrong. + */ + void formatJSON(OutputStream stream, JSONFormat format) throws IOException; + + /** + * Like {@link #formatJSON()}, but the data is output onto a {@link Writer}. + * + * @throws IOException - an unchecked wrapper for {@link java.io.IOException}, if anything goes wrong. + */ + void formatJSON(Writer writer) throws IOException; + + /** + * Like {@link #formatJSON(JSONFormat)}, but the data is output onto a {@link Writer}. + * + * @throws IOException - an unchecked wrapper for {@link java.io.IOException}, if anything goes wrong. + */ + void formatJSON(Writer writer, JSONFormat format) throws IOException; + /** * Get this record formatted as XML. * diff --git a/jOOQ/src/main/java/org/jooq/impl/AbstractRecord.java b/jOOQ/src/main/java/org/jooq/impl/AbstractRecord.java index 1d7e102c62..e41b748c70 100644 --- a/jOOQ/src/main/java/org/jooq/impl/AbstractRecord.java +++ b/jOOQ/src/main/java/org/jooq/impl/AbstractRecord.java @@ -67,6 +67,7 @@ import org.jooq.Attachable; import org.jooq.Converter; import org.jooq.DataType; import org.jooq.Field; +import org.jooq.JSONFormat; import org.jooq.Name; import org.jooq.Record; import org.jooq.Record1; @@ -104,6 +105,8 @@ import org.jooq.impl.Tools.ThreadGuard.GuardedOperation; import org.jooq.tools.Convert; import org.jooq.tools.JooqLogger; import org.jooq.tools.StringUtils; +import org.jooq.tools.json.JSONArray; +import org.jooq.tools.json.JSONObject; /** * A general base class for all {@link Record} types @@ -1003,6 +1006,57 @@ abstract class AbstractRecord extends AbstractStore implements Record { // Formatting methods // ------------------------------------------------------------------------- + @Override + public final String formatJSON() { + StringWriter writer = new StringWriter(); + formatJSON(writer); + return writer.toString(); + } + + @Override + public final String formatJSON(JSONFormat format) { + StringWriter writer = new StringWriter(); + formatJSON(writer, format); + return writer.toString(); + } + + @Override + public final void formatJSON(OutputStream stream) { + formatJSON(new OutputStreamWriter(stream)); + } + + @Override + public final void formatJSON(OutputStream stream, JSONFormat format) { + formatJSON(new OutputStreamWriter(stream), format); + } + + @Override + public final void formatJSON(Writer writer) { + formatJSON(writer, JSONFormat.DEFAULT_FOR_RECORDS); + } + + @Override + public final void formatJSON(Writer writer, JSONFormat format) { + if (format.header()) + log.debug("JSONFormat.header currently not supported for Record.formatJSON()"); + + try { + switch (format.recordFormat()) { + case ARRAY: + writer.append(JSONArray.toJSONString(ResultImpl.formatJSONArray0(this, fields.fields))); + break; + case OBJECT: + writer.append(JSONObject.toJSONString(ResultImpl.formatJSONMap0(this, fields.fields))); + break; + default: + throw new IllegalArgumentException("Format not supported: " + format); + } + } + catch (java.io.IOException e) { + throw new IOException("Exception while writing JSON", e); + } + } + @Override public final String formatXML() { return formatXML(XMLFormat.DEFAULT_FOR_RECORDS); diff --git a/jOOQ/src/main/java/org/jooq/impl/ResultImpl.java b/jOOQ/src/main/java/org/jooq/impl/ResultImpl.java index a1779e7e75..a4f14a588d 100644 --- a/jOOQ/src/main/java/org/jooq/impl/ResultImpl.java +++ b/jOOQ/src/main/java/org/jooq/impl/ResultImpl.java @@ -817,7 +817,7 @@ final class ResultImpl implements Result, AttachableInterna } } - private final Object formatJSON0(Object value) { + private static final Object formatJSON0(Object value) { // [#2741] TODO: This logic will be externalised in new SPI if (value instanceof byte[]) @@ -894,7 +894,7 @@ final class ResultImpl implements Result, AttachableInterna @Override public final void formatJSON(Writer writer) { - formatJSON(writer, new JSONFormat()); + formatJSON(writer, JSONFormat.DEFAULT_FOR_RESULTS); } @Override @@ -931,25 +931,13 @@ final class ResultImpl implements Result, AttachableInterna switch (format.recordFormat()) { case ARRAY: - for (Record record : this) { - List list = new ArrayList(); - - for (int index = 0; index < fields.fields.length; index++) - list.add(formatJSON0(record.get(index))); - - r.add(list); - } + for (Record record : this) + r.add(formatJSONArray0(record, fields)); break; case OBJECT: - for (Record record : this) { - Map map = new LinkedHashMap(); - - for (int index = 0; index < fields.fields.length; index++) - map.put(record.field(index).getName(), formatJSON0(record.get(index))); - - r.add(map); - } + for (Record record : this) + r.add(formatJSONMap0(record, fields)); break; default: @@ -975,6 +963,24 @@ final class ResultImpl implements Result, AttachableInterna } } + static final Map formatJSONMap0(Record record, Fields fields) { + Map map = new LinkedHashMap(); + + for (int index = 0; index < fields.fields.length; index++) + map.put(record.field(index).getName(), formatJSON0(record.get(index))); + + return map; + } + + static final List formatJSONArray0(Record record, Fields fields) { + List list = new ArrayList(); + + for (int index = 0; index < fields.fields.length; index++) + list.add(formatJSON0(record.get(index))); + + return list; + } + @Override public final String formatXML() { return formatXML(XMLFormat.DEFAULT_FOR_RESULTS);