NIFI-3873: Improve Avro logical types readability

Signed-off-by: Matt Burgess <mattyb149@apache.org>

This closes #1788
This commit is contained in:
Koji Kawamura 2017-05-12 13:30:31 +09:00 committed by Matt Burgess
parent 2dde480029
commit 3fd7d3b272
2 changed files with 28 additions and 2 deletions

View File

@ -63,6 +63,11 @@
<groupId>org.apache.avro</groupId> <groupId>org.apache.avro</groupId>
<artifactId>avro</artifactId> <artifactId>avro</artifactId>
</dependency> </dependency>
<dependency>
<groupId>joda-time</groupId>
<artifactId>joda-time</artifactId>
<scope>compile</scope>
</dependency>
<dependency> <dependency>
<groupId>org.xerial.snappy</groupId> <groupId>org.xerial.snappy</groupId>
<artifactId>snappy-java</artifactId> <artifactId>snappy-java</artifactId>

View File

@ -18,11 +18,16 @@ package org.apache.nifi.web;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.avro.Conversions;
import org.apache.avro.data.TimeConversions;
import org.apache.avro.file.DataFileStream; import org.apache.avro.file.DataFileStream;
import org.apache.avro.generic.GenericData; import org.apache.avro.generic.GenericData;
import org.apache.avro.generic.GenericDatumReader; import org.apache.avro.generic.GenericDatumReader;
import org.apache.avro.io.DatumReader; import org.apache.avro.io.DatumReader;
import org.apache.nifi.web.ViewableContent.DisplayMode; import org.apache.nifi.web.ViewableContent.DisplayMode;
import org.joda.time.DateTime;
import org.joda.time.LocalDate;
import org.joda.time.LocalTime;
import javax.servlet.ServletException; import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServlet;
@ -103,11 +108,27 @@ public class StandardContentViewerController extends HttpServlet {
} else if ("application/avro-binary".equals(contentType) || "avro/binary".equals(contentType) || "application/avro+binary".equals(contentType)) { } else if ("application/avro-binary".equals(contentType) || "avro/binary".equals(contentType) || "application/avro+binary".equals(contentType)) {
final StringBuilder sb = new StringBuilder(); final StringBuilder sb = new StringBuilder();
sb.append("["); sb.append("[");
final DatumReader<GenericData.Record> datumReader = new GenericDatumReader<>(); // Use Avro conversions to display logical type values in human readable way.
final GenericData genericData = new GenericData(){
@Override
protected void toString(Object datum, StringBuilder buffer) {
// Since these types are not quoted and produce a malformed JSON string, quote it here.
if (datum instanceof LocalDate || datum instanceof LocalTime || datum instanceof DateTime) {
buffer.append("\"").append(datum).append("\"");
return;
}
super.toString(datum, buffer);
}
};
genericData.addLogicalTypeConversion(new Conversions.DecimalConversion());
genericData.addLogicalTypeConversion(new TimeConversions.DateConversion());
genericData.addLogicalTypeConversion(new TimeConversions.TimeConversion());
genericData.addLogicalTypeConversion(new TimeConversions.TimestampConversion());
final DatumReader<GenericData.Record> datumReader = new GenericDatumReader<>(null, null, genericData);
try (final DataFileStream<GenericData.Record> dataFileReader = new DataFileStream<>(content.getContentStream(), datumReader)) { try (final DataFileStream<GenericData.Record> dataFileReader = new DataFileStream<>(content.getContentStream(), datumReader)) {
while (dataFileReader.hasNext()) { while (dataFileReader.hasNext()) {
final GenericData.Record record = dataFileReader.next(); final GenericData.Record record = dataFileReader.next();
final String formattedRecord = record.toString(); final String formattedRecord = genericData.toString(record);
sb.append(formattedRecord); sb.append(formattedRecord);
sb.append(","); sb.append(",");
// Do not format more than 10 MB of content. // Do not format more than 10 MB of content.