Java tutorial
/** * Copyright 2013 Julien Silland * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package io.soliton.protobuf.json; import com.google.common.base.CaseFormat; import com.google.common.io.BaseEncoding; import com.google.gson.JsonArray; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonPrimitive; import com.google.protobuf.ByteString; import com.google.protobuf.Descriptors; import com.google.protobuf.Message; import java.util.List; import java.util.Map; /** * Static utility methods pertaining to instances of {@link Message} objects. * * @author Julien Silland (julien@soliton.io) */ public class Messages { /** * Non-instantiatable class */ private Messages() { } /** * Converts a proto-message into an equivalent JSON representation. * * @param output */ public static JsonObject toJson(Message output) { JsonObject object = new JsonObject(); for (Map.Entry<Descriptors.FieldDescriptor, Object> field : output.getAllFields().entrySet()) { String jsonName = CaseFormat.LOWER_UNDERSCORE.to(CaseFormat.LOWER_CAMEL, field.getKey().getName()); if (field.getKey().isRepeated()) { JsonArray array = new JsonArray(); List<?> items = (List<?>) field.getValue(); for (Object item : items) { array.add(serializeField(field.getKey(), item)); } object.add(jsonName, array); } else { object.add(jsonName, serializeField(field.getKey(), field.getValue())); } } return object; } private static JsonElement serializeField(Descriptors.FieldDescriptor field, Object value) { switch (field.getType()) { case DOUBLE: return new JsonPrimitive((Double) value); case FLOAT: return new JsonPrimitive((Float) value); case INT64: case UINT64: case FIXED64: case SINT64: case SFIXED64: return new JsonPrimitive((Long) value); case INT32: case UINT32: case FIXED32: case SINT32: case SFIXED32: return new JsonPrimitive((Integer) value); case BOOL: return new JsonPrimitive((Boolean) value); case STRING: return new JsonPrimitive((String) value); case GROUP: case MESSAGE: return toJson((Message) value); case BYTES: return new JsonPrimitive(BaseEncoding.base64().encode(((ByteString) value).toByteArray())); case ENUM: String protoEnumName = ((Descriptors.EnumValueDescriptor) value).getName(); return new JsonPrimitive(CaseFormat.UPPER_UNDERSCORE.to(CaseFormat.LOWER_CAMEL, protoEnumName)); } return null; } /** * Converts a JSON object to a protobuf message * * @param builder the proto message type builder * @param input the JSON object to convert */ public static Message fromJson(Message.Builder builder, JsonObject input) throws Exception { Descriptors.Descriptor descriptor = builder.getDescriptorForType(); for (Map.Entry<String, JsonElement> entry : input.entrySet()) { String protoName = CaseFormat.LOWER_CAMEL.to(CaseFormat.LOWER_UNDERSCORE, entry.getKey()); Descriptors.FieldDescriptor field = descriptor.findFieldByName(protoName); if (field == null) { throw new Exception("Can't find descriptor for field " + protoName); } if (field.isRepeated()) { if (!entry.getValue().isJsonArray()) { // fail } JsonArray array = entry.getValue().getAsJsonArray(); for (JsonElement item : array) { builder.addRepeatedField(field, parseField(field, item, builder)); } } else { builder.setField(field, parseField(field, entry.getValue(), builder)); } } return builder.build(); } private static Object parseField(Descriptors.FieldDescriptor field, JsonElement value, Message.Builder enclosingBuilder) throws Exception { switch (field.getType()) { case DOUBLE: if (!value.isJsonPrimitive()) { // fail; } return value.getAsDouble(); case FLOAT: if (!value.isJsonPrimitive()) { // fail; } return value.getAsFloat(); case INT64: case UINT64: case FIXED64: case SINT64: case SFIXED64: if (!value.isJsonPrimitive()) { // fail } return value.getAsLong(); case INT32: case UINT32: case FIXED32: case SINT32: case SFIXED32: if (!value.isJsonPrimitive()) { // fail } return value.getAsInt(); case BOOL: if (!value.isJsonPrimitive()) { // fail } return value.getAsBoolean(); case STRING: if (!value.isJsonPrimitive()) { // fail } return value.getAsString(); case GROUP: case MESSAGE: if (!value.isJsonObject()) { // fail } return fromJson(enclosingBuilder.newBuilderForField(field), value.getAsJsonObject()); case BYTES: if (!value.isJsonPrimitive()) { // fail } return ByteString.copyFrom(BaseEncoding.base64().decode(value.getAsString())); case ENUM: if (!value.isJsonPrimitive()) { // fail } String protoEnumValue = CaseFormat.LOWER_CAMEL.to(CaseFormat.UPPER_UNDERSCORE, value.getAsString()); return field.getEnumType().findValueByName(protoEnumValue); } return null; } }