You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@avro.apache.org by cu...@apache.org on 2010/12/16 22:54:54 UTC
svn commit: r1050184 - in /avro/trunk: CHANGES.txt
lang/java/avro/src/main/java/org/apache/avro/generic/GenericData.java
lang/java/avro/src/test/java/org/apache/avro/generic/TestGenericData.java
Author: cutting
Date: Thu Dec 16 21:54:53 2010
New Revision: 1050184
URL: http://svn.apache.org/viewvc?rev=1050184&view=rev
Log:
AVRO-713. Java: Fix GenericData.Record#toString() to produce valid JSON for enum symbols. Contributed by Jay Kreps.
Modified:
avro/trunk/CHANGES.txt
avro/trunk/lang/java/avro/src/main/java/org/apache/avro/generic/GenericData.java
avro/trunk/lang/java/avro/src/test/java/org/apache/avro/generic/TestGenericData.java
Modified: avro/trunk/CHANGES.txt
URL: http://svn.apache.org/viewvc/avro/trunk/CHANGES.txt?rev=1050184&r1=1050183&r2=1050184&view=diff
==============================================================================
--- avro/trunk/CHANGES.txt (original)
+++ avro/trunk/CHANGES.txt Thu Dec 16 21:54:53 2010
@@ -98,6 +98,9 @@ Avro 1.5.0 (unreleased)
AVRO-710. Java: Add bounds checking to GenericData.Array#get(int).
(Bo Shi via cutting)
+ AVRO-713. Java: Fix GenericData.Record#toString() to produce valid
+ JSON for enum symbols. (Jay Kreps via cutting)
+
Avro 1.4.1 (13 October 2010)
NEW FEATURES
Modified: avro/trunk/lang/java/avro/src/main/java/org/apache/avro/generic/GenericData.java
URL: http://svn.apache.org/viewvc/avro/trunk/lang/java/avro/src/main/java/org/apache/avro/generic/GenericData.java?rev=1050184&r1=1050183&r2=1050184&view=diff
==============================================================================
--- avro/trunk/lang/java/avro/src/main/java/org/apache/avro/generic/GenericData.java (original)
+++ avro/trunk/lang/java/avro/src/main/java/org/apache/avro/generic/GenericData.java Thu Dec 16 21:54:53 2010
@@ -310,9 +310,10 @@ public class GenericData {
buffer.append(", ");
}
buffer.append("}");
- } else if (datum instanceof CharSequence) {
+ } else if (datum instanceof CharSequence
+ || datum instanceof GenericEnumSymbol) {
buffer.append("\"");
- buffer.append(datum); // TODO: properly escape!
+ writeEscapedString(datum.toString(), buffer);
buffer.append("\"");
} else if (datum instanceof ByteBuffer) {
buffer.append("{\"bytes\": \"");
@@ -324,6 +325,50 @@ public class GenericData {
buffer.append(datum);
}
}
+
+ /* Adapted from http://code.google.com/p/json-simple */
+ private void writeEscapedString(String string, StringBuilder builder) {
+ for(int i = 0; i < string.length(); i++){
+ char ch = string.charAt(i);
+ switch(ch){
+ case '"':
+ builder.append("\\\"");
+ break;
+ case '\\':
+ builder.append("\\\\");
+ break;
+ case '\b':
+ builder.append("\\b");
+ break;
+ case '\f':
+ builder.append("\\f");
+ break;
+ case '\n':
+ builder.append("\\n");
+ break;
+ case '\r':
+ builder.append("\\r");
+ break;
+ case '\t':
+ builder.append("\\t");
+ break;
+ case '/':
+ builder.append("\\/");
+ break;
+ default:
+ // Reference: http://www.unicode.org/versions/Unicode5.1.0/
+ if((ch>='\u0000' && ch<='\u001F') || (ch>='\u007F' && ch<='\u009F') || (ch>='\u2000' && ch<='\u20FF')){
+ String hex = Integer.toHexString(ch);
+ builder.append("\\u");
+ for(int j = 0; j < 4-builder.length(); j++)
+ builder.append('0');
+ builder.append(string.toUpperCase());
+ } else {
+ builder.append(ch);
+ }
+ }
+ }
+ }
/** Create a schema given an example datum. */
public Schema induce(Object datum) {
Modified: avro/trunk/lang/java/avro/src/test/java/org/apache/avro/generic/TestGenericData.java
URL: http://svn.apache.org/viewvc/avro/trunk/lang/java/avro/src/test/java/org/apache/avro/generic/TestGenericData.java?rev=1050184&r1=1050183&r2=1050184&view=diff
==============================================================================
--- avro/trunk/lang/java/avro/src/test/java/org/apache/avro/generic/TestGenericData.java (original)
+++ avro/trunk/lang/java/avro/src/test/java/org/apache/avro/generic/TestGenericData.java Thu Dec 16 21:54:53 2010
@@ -17,6 +17,7 @@
*/
package org.apache.avro.generic;
+import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Collection;
@@ -31,6 +32,10 @@ import org.apache.avro.Schema.Field;
import org.apache.avro.AvroRuntimeException;
import org.apache.avro.Schema.Type;
import org.apache.avro.util.Utf8;
+import org.codehaus.jackson.JsonFactory;
+import org.codehaus.jackson.JsonParseException;
+import org.codehaus.jackson.JsonParser;
+import org.codehaus.jackson.map.ObjectMapper;
import org.junit.Test;
@@ -141,4 +146,24 @@ public class TestGenericData {
fail("Expected IndexOutOfBoundsException getting index 0 after clear()");
} catch (IndexOutOfBoundsException e) {}
}
+
+ @Test
+ public void testToStringIsJson() throws JsonParseException, IOException {
+ Field stringField = new Field("string", Schema.create(Type.STRING), null, null);
+ Field enumField = new Field("enum", Schema.createEnum("my_enum", "doc", null, Arrays.asList("a", "b", "c")), null, null);
+ Schema schema = Schema.createRecord("my_record", "doc", "mytest", false);
+ schema.setFields(Arrays.asList(stringField, enumField));
+
+ GenericRecord r = new GenericData.Record(schema);
+ r.put(stringField.name(), "hello\nthere\"\tyou}");
+ r.put(enumField.name(), new GenericData.EnumSymbol("a"));
+
+ String json = r.toString();
+ JsonFactory factory = new JsonFactory();
+ JsonParser parser = factory.createJsonParser(json);
+ ObjectMapper mapper = new ObjectMapper();
+
+ // will throw exception if string is not parsable json
+ mapper.readTree(parser);
+ }
}