package protobuf.codec.json; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.util.Iterator; import java.util.List; import java.util.Map; import org.apache.commons.codec.binary.Base64; import org.codehaus.jackson.JsonGenerator; import protobuf.codec.AbstractCodec; import protobuf.codec.Codec.Feature; import com.google.protobuf.ByteString; import com.google.protobuf.Descriptors.EnumValueDescriptor; import com.google.protobuf.Descriptors.FieldDescriptor; import com.google.protobuf.Message; import com.google.protobuf.UnknownFieldSet; /** * Jackson json writer * * @author sijuv * */ public class JacksonJsonWriter { public static void generateJSONFields(Message message, JsonGenerator generator, Map<Feature, Object> featureMap) throws IOException { generator.configure(org.codehaus.jackson.JsonGenerator.Feature.AUTO_CLOSE_TARGET, (Boolean) featureMap.get(Feature.CLOSE_STREAM)); if (AbstractCodec.prettyPrint(featureMap)) { generator.useDefaultPrettyPrinter(); } if (!AbstractCodec.closeStream(featureMap)) { generator.configure(org.codehaus.jackson.JsonGenerator.Feature.AUTO_CLOSE_TARGET, false); } generator.writeStartObject(); Iterator<Map.Entry<FieldDescriptor, Object>> iterator = message.getAllFields().entrySet().iterator(); // Get all set fields while (iterator.hasNext()) { Map.Entry<FieldDescriptor, Object> record = iterator.next(); FieldDescriptor field = record.getKey(); String fieldName = field.isExtension() ? JsonCodec.getExtensionFieldName(field.getName(), featureMap) : field.getName(); // If extn field? box fieldName = AbstractCodec.substituteFieldNameForWriting(fieldName, featureMap); Object value = record.getValue(); if (field.isRepeated()) { generator.writeArrayFieldStart(fieldName); Iterator<?> iter = ((List<?>) value).iterator(); while (iter.hasNext()) { writeFieldValue(field, iter.next(), generator, featureMap); } generator.writeEndArray(); } else { generator.writeFieldName(fieldName); writeFieldValue(field, value, generator, featureMap); } } if (AbstractCodec.supportUnknownFields(featureMap)) { writeUnknownFieldSet(message.getUnknownFields(), generator, featureMap); } generator.writeEndObject(); } // Extract the field value depending on its java type private static void writeFieldValue(FieldDescriptor fieldDesc, Object value, JsonGenerator generator, Map<Feature, Object> featureMap) throws IOException { switch (fieldDesc.getJavaType()) { case INT: generator.writeNumber((Integer) value); break; case LONG: generator.writeNumber((Long) value); break; case FLOAT: generator.writeNumber((Float) value); break; case DOUBLE: generator.writeNumber((Double) value); break; case BOOLEAN: generator.writeBoolean((Boolean) value); break; case STRING: generator.writeString((String) value); break; case ENUM: generator.writeString(((EnumValueDescriptor) value).getName()); break; case BYTE_STRING: generator.writeString(Base64.encodeBase64String(((ByteString) value).toByteArray())); break; case MESSAGE: generateJSONFields((Message) value, generator, featureMap); break; default: throw new UnsupportedEncodingException( String.format( "Unspupported protobuf java field type [%s] for field [%s] ", fieldDesc.getJavaType(), fieldDesc.getName())); } } private static void writeUnknownFieldSet(UnknownFieldSet unknownFields, JsonGenerator generator, Map<Feature, Object> featureMap) throws IOException { if (unknownFields != null && unknownFields.asMap().size() > 0) { generator.writeStringField(AbstractCodec.getUnknownFieldElementName(featureMap), AbstractCodec.encodeUnknownFieldsToString(unknownFields)); } } }