@Override public void doMerge(JsonParser parser, int currentDepth, Message.Builder messageBuilder) throws IOException { Value.Builder builder = (Value.Builder) messageBuilder; JsonToken token = parser.currentToken(); if (token.isBoolean()) { builder.setBoolValue(ParseSupport.parseBool(parser)); } else if (token.isNumeric()) { builder.setNumberValue(ParseSupport.parseDouble(parser)); } else if (token == JsonToken.VALUE_NULL) { builder.setNullValue(NullValue.NULL_VALUE); } else if (token.isScalarValue()) { builder.setStringValue(ParseSupport.parseString(parser)); } else if (token == JsonToken.START_OBJECT) { Struct.Builder structBuilder = builder.getStructValueBuilder(); StructMarshaller.INSTANCE.mergeValue(parser, currentDepth + 1, structBuilder); } else if (token == JsonToken.START_ARRAY) { ListValue.Builder listValueBuilder = builder.getListValueBuilder(); ListValueMarshaller.INSTANCE.mergeValue(parser, currentDepth + 1, listValueBuilder); } else { throw new IllegalStateException("Unexpected json data: " + parser.getText()); } }
@Test public void anyInMaps() throws Exception { TestAny.Builder testAny = TestAny.newBuilder(); testAny.putAnyMap("int32_wrapper", Any.pack(Int32Value.newBuilder().setValue(123).build())); testAny.putAnyMap("int64_wrapper", Any.pack(Int64Value.newBuilder().setValue(456).build())); testAny.putAnyMap("timestamp", Any.pack(Timestamps.parse("1969-12-31T23:59:59Z"))); testAny.putAnyMap("duration", Any.pack(Durations.parse("12345.1s"))); testAny.putAnyMap("field_mask", Any.pack(FieldMaskUtil.fromString("foo.bar,baz"))); Value numberValue = Value.newBuilder().setNumberValue(1.125).build(); Struct.Builder struct = Struct.newBuilder(); struct.putFields("number", numberValue); testAny.putAnyMap("struct", Any.pack(struct.build())); Value nullValue = Value.newBuilder().setNullValue(NullValue.NULL_VALUE).build(); testAny.putAnyMap( "list_value", Any.pack(ListValue.newBuilder().addValues(numberValue).addValues(nullValue).build())); testAny.putAnyMap("number_value", Any.pack(numberValue)); testAny.putAnyMap("any_value_number", Any.pack(Any.pack(numberValue))); testAny.putAnyMap("any_value_default", Any.pack(Any.getDefaultInstance())); testAny.putAnyMap("default", Any.getDefaultInstance()); assertMatchesUpstream(testAny.build(), TestAllTypes.getDefaultInstance()); }
@Test public void includingDefaultValueFields() throws Exception { TestAllTypes message = TestAllTypes.getDefaultInstance(); assertMatchesUpstream(message); assertMatchesUpstream(message, true, false, false); TestMap mapMessage = TestMap.getDefaultInstance(); assertMatchesUpstream(mapMessage); assertMatchesUpstream(mapMessage, true, false, false); TestOneof oneofMessage = TestOneof.getDefaultInstance(); assertMatchesUpstream(oneofMessage); assertMatchesUpstream(oneofMessage, true, false, false); oneofMessage = TestOneof.newBuilder().setOneofInt32(42).build(); assertMatchesUpstream(oneofMessage); assertMatchesUpstream(oneofMessage, true, false, false); oneofMessage = TestOneof.newBuilder().setOneofNullValue(NullValue.NULL_VALUE).build(); assertMatchesUpstream(oneofMessage); assertMatchesUpstream(oneofMessage, true, false, false); }
/** * Determines whether we skip processing of the field if it is null. We usually skip null values * in the JSON to treat them as default, but must actually process the null for {@link Value} and * {@link NullValue} because it means their value must be set. */ private boolean mustSkipNull(FieldDescriptor field) { if (field.isRepeated()) { return true; } if (field.getJavaType() == JavaType.MESSAGE && field.getMessageType() == Value.getDescriptor()) { return false; } if (field.getJavaType() == JavaType.ENUM && field.getEnumType() == NullValue.getDescriptor()) { return false; } return true; }
@Test public void nullInOneOf() throws Exception { TestOneof.Builder builder = TestOneof.newBuilder(); mergeFromJson("{\n" + " \"oneofNullValue\": null \n" + "}", builder); TestOneof message = builder.build(); assertEquals(TestOneof.OneofFieldCase.ONEOF_NULL_VALUE, message.getOneofFieldCase()); assertEquals(NullValue.NULL_VALUE, message.getOneofNullValue()); }
/** * Creates additional Enums (NullValue) to be added to the Service config. */ // TODO (guptasu): Fix this hack. Find a better way to add the predefined types. // TODO (guptasu): Add them only when required and not in all cases. static Iterable<Enum> createAdditionalServiceEnums() { // TODO (guptasu): Remove this hard coding. Without this, creation of Model from Service throws. // Needs investigation. String fileName = "struct.proto"; List<Enum> additionalEnums = Lists.newArrayList(); additionalEnums.add(TypesBuilderFromDescriptor.createEnum(NullValue.getDescriptor().getFullName(), NullValue.getDescriptor().toProto(), fileName)); return additionalEnums; }
public void testNullInOneof() throws Exception { TestOneof.Builder builder = TestOneof.newBuilder(); mergeFromJson("{\n" + " \"oneofNullValue\": null \n" + "}", builder); TestOneof message = builder.build(); assertEquals(TestOneof.OneofFieldCase.ONEOF_NULL_VALUE, message.getOneofFieldCase()); assertEquals(NullValue.NULL_VALUE, message.getOneofNullValue()); }
private StackManipulation printValue( Map<String, FieldDescription> fieldsByName, ProtoFieldInfo info) { boolean repeated = !info.isMapField() && info.isRepeated(); switch (info.valueType()) { case INT32: case SINT32: case SFIXED32: return repeated ? SerializeSupport_printRepeatedSignedInt32 : SerializeSupport_printSignedInt32; case INT64: case SINT64: case SFIXED64: return repeated ? SerializeSupport_printRepeatedSignedInt64 : SerializeSupport_printSignedInt64; case BOOL: return repeated ? SerializeSupport_printRepeatedBool : SerializeSupport_printBool; case FLOAT: return repeated ? SerializeSupport_printRepeatedFloat : SerializeSupport_printFloat; case DOUBLE: return repeated ? SerializeSupport_printRepeatedDouble : SerializeSupport_printDouble; case UINT32: case FIXED32: return repeated ? SerializeSupport_printRepeatedUnsignedInt32 : SerializeSupport_printUnsignedInt32; case UINT64: case FIXED64: return repeated ? SerializeSupport_printRepeatedUnsignedInt64 : SerializeSupport_printUnsignedInt64; case STRING: return repeated ? SerializeSupport_printRepeatedString : SerializeSupport_printString; case BYTES: return repeated ? SerializeSupport_printRepeatedBytes : SerializeSupport_printBytes; case ENUM: // Special-case google.protobuf.NullValue (it's an Enum). if (info.valueField().descriptor().getEnumType().equals(NullValue.getDescriptor())) { return repeated ? SerializeSupport_printRepeatedNull : SerializeSupport_printNull; } else { return new StackManipulation.Compound( CodeGenUtil.getEnumDescriptor(info), repeated ? SerializeSupport_printRepeatedEnum : SerializeSupport_printEnum); } case MESSAGE: case GROUP: return new StackManipulation.Compound( FieldAccess.forField( fieldsByName.get( CodeGenUtil.fieldNameForNestedMarshaller( info.valueField().descriptor().getMessageType()))) .read(), repeated ? SerializeSupport_printRepeatedMessage : SerializeSupport_printMessage); default: throw new IllegalStateException("Unknown field type."); } }
@Test public void anyFields() throws Exception { TestAllTypes content = TestAllTypes.newBuilder().setOptionalInt32(1234).build(); TestAny message = TestAny.newBuilder().setAnyValue(Any.pack(content)).build(); assertMatchesUpstream(message, TestAllTypes.getDefaultInstance()); TestAny messageWithDefaultAnyValue = TestAny.newBuilder().setAnyValue(Any.getDefaultInstance()).build(); assertMatchesUpstream(messageWithDefaultAnyValue); // Well-known types have a special formatting when embedded in Any. // // 1. Any in Any. Any anyMessage = Any.pack(Any.pack(content)); assertMatchesUpstream(anyMessage, TestAllTypes.getDefaultInstance()); // 2. Wrappers in Any. anyMessage = Any.pack(Int32Value.newBuilder().setValue(12345).build()); assertMatchesUpstream(anyMessage, TestAllTypes.getDefaultInstance()); anyMessage = Any.pack(UInt32Value.newBuilder().setValue(12345).build()); assertMatchesUpstream(anyMessage, TestAllTypes.getDefaultInstance()); anyMessage = Any.pack(Int64Value.newBuilder().setValue(12345).build()); assertMatchesUpstream(anyMessage, TestAllTypes.getDefaultInstance()); anyMessage = Any.pack(UInt64Value.newBuilder().setValue(12345).build()); assertMatchesUpstream(anyMessage, TestAllTypes.getDefaultInstance()); anyMessage = Any.pack(FloatValue.newBuilder().setValue(12345).build()); assertMatchesUpstream(anyMessage, TestAllTypes.getDefaultInstance()); anyMessage = Any.pack(DoubleValue.newBuilder().setValue(12345).build()); assertMatchesUpstream(anyMessage, TestAllTypes.getDefaultInstance()); anyMessage = Any.pack(BoolValue.newBuilder().setValue(true).build()); assertMatchesUpstream(anyMessage, TestAllTypes.getDefaultInstance()); anyMessage = Any.pack(StringValue.newBuilder().setValue("Hello").build()); assertMatchesUpstream(anyMessage, TestAllTypes.getDefaultInstance()); anyMessage = Any.pack(BytesValue.newBuilder().setValue(ByteString.copyFrom(new byte[] {1, 2})).build()); assertMatchesUpstream(anyMessage, TestAllTypes.getDefaultInstance()); // 3. Timestamp in Any. anyMessage = Any.pack(Timestamps.parse("1969-12-31T23:59:59Z")); assertMatchesUpstream(anyMessage, TestAllTypes.getDefaultInstance()); // 4. Duration in Any anyMessage = Any.pack(Durations.parse("12345.10s")); assertMatchesUpstream(anyMessage, TestAllTypes.getDefaultInstance()); // 5. FieldMask in Any anyMessage = Any.pack(FieldMaskUtil.fromString("foo.bar,baz")); assertMatchesUpstream(anyMessage, TestAllTypes.getDefaultInstance()); // 6. Struct in Any Struct.Builder structBuilder = Struct.newBuilder(); structBuilder.putFields("number", Value.newBuilder().setNumberValue(1.125).build()); anyMessage = Any.pack(structBuilder.build()); assertMatchesUpstream(anyMessage, TestAllTypes.getDefaultInstance()); // 7. Value (number type) in Any Value.Builder valueBuilder = Value.newBuilder(); valueBuilder.setNumberValue(1); anyMessage = Any.pack(valueBuilder.build()); assertMatchesUpstream(anyMessage, TestAllTypes.getDefaultInstance()); // 8. Value (null type) in Any anyMessage = Any.pack(Value.newBuilder().setNullValue(NullValue.NULL_VALUE).build()); assertMatchesUpstream(anyMessage, TestAllTypes.getDefaultInstance()); }
private Object parseFieldValue(FieldDescriptor field, JsonElement json, Message.Builder builder) throws InvalidProtocolBufferException { if (json instanceof JsonNull) { if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE && field.getMessageType().getFullName().equals(Value.getDescriptor().getFullName())) { // For every other type, "null" means absence, but for the special // Value message, it means the "null_value" field has been set. Value value = Value.newBuilder().setNullValueValue(0).build(); return builder.newBuilderForField(field).mergeFrom(value.toByteString()).build(); } else if (field.getJavaType() == FieldDescriptor.JavaType.ENUM && field.getEnumType().getFullName().equals(NullValue.getDescriptor().getFullName())) { // If the type of the field is a NullValue, then the value should be explicitly set. return field.getEnumType().findValueByNumber(0); } return null; } switch (field.getType()) { case INT32: case SINT32: case SFIXED32: return parseInt32(json); case INT64: case SINT64: case SFIXED64: return parseInt64(json); case BOOL: return parseBool(json); case FLOAT: return parseFloat(json); case DOUBLE: return parseDouble(json); case UINT32: case FIXED32: return parseUint32(json); case UINT64: case FIXED64: return parseUint64(json); case STRING: return parseString(json); case BYTES: return parseBytes(json); case ENUM: return parseEnum(field.getEnumType(), json); case MESSAGE: case GROUP: if (currentDepth >= recursionLimit) { throw new InvalidProtocolBufferException("Hit recursion limit."); } ++currentDepth; Message.Builder subBuilder = builder.newBuilderForField(field); merge(json, subBuilder); --currentDepth; return subBuilder.build(); default: throw new InvalidProtocolBufferException("Invalid field type: " + field.getType()); } }
public void testAnyInMaps() throws Exception { JsonFormat.TypeRegistry registry = JsonFormat.TypeRegistry.newBuilder().add(TestAllTypes.getDescriptor()).build(); JsonFormat.Printer printer = JsonFormat.printer().usingTypeRegistry(registry); TestAny.Builder testAny = TestAny.newBuilder(); testAny.putAnyMap("int32_wrapper", Any.pack(Int32Value.newBuilder().setValue(123).build())); testAny.putAnyMap("int64_wrapper", Any.pack(Int64Value.newBuilder().setValue(456).build())); testAny.putAnyMap("timestamp", Any.pack(Timestamps.parse("1969-12-31T23:59:59Z"))); testAny.putAnyMap("duration", Any.pack(Durations.parse("12345.1s"))); testAny.putAnyMap("field_mask", Any.pack(FieldMaskUtil.fromString("foo.bar,baz"))); Value numberValue = Value.newBuilder().setNumberValue(1.125).build(); Struct.Builder struct = Struct.newBuilder(); struct.putFields("number", numberValue); testAny.putAnyMap("struct", Any.pack(struct.build())); Value nullValue = Value.newBuilder().setNullValue(NullValue.NULL_VALUE).build(); testAny.putAnyMap( "list_value", Any.pack(ListValue.newBuilder().addValues(numberValue).addValues(nullValue).build())); testAny.putAnyMap("number_value", Any.pack(numberValue)); testAny.putAnyMap("any_value_number", Any.pack(Any.pack(numberValue))); testAny.putAnyMap("any_value_default", Any.pack(Any.getDefaultInstance())); testAny.putAnyMap("default", Any.getDefaultInstance()); assertEquals( "{\n" + " \"anyMap\": {\n" + " \"int32_wrapper\": {\n" + " \"@type\": \"type.googleapis.com/google.protobuf.Int32Value\",\n" + " \"value\": 123\n" + " },\n" + " \"int64_wrapper\": {\n" + " \"@type\": \"type.googleapis.com/google.protobuf.Int64Value\",\n" + " \"value\": \"456\"\n" + " },\n" + " \"timestamp\": {\n" + " \"@type\": \"type.googleapis.com/google.protobuf.Timestamp\",\n" + " \"value\": \"1969-12-31T23:59:59Z\"\n" + " },\n" + " \"duration\": {\n" + " \"@type\": \"type.googleapis.com/google.protobuf.Duration\",\n" + " \"value\": \"12345.100s\"\n" + " },\n" + " \"field_mask\": {\n" + " \"@type\": \"type.googleapis.com/google.protobuf.FieldMask\",\n" + " \"value\": \"foo.bar,baz\"\n" + " },\n" + " \"struct\": {\n" + " \"@type\": \"type.googleapis.com/google.protobuf.Struct\",\n" + " \"value\": {\n" + " \"number\": 1.125\n" + " }\n" + " },\n" + " \"list_value\": {\n" + " \"@type\": \"type.googleapis.com/google.protobuf.ListValue\",\n" + " \"value\": [1.125, null]\n" + " },\n" + " \"number_value\": {\n" + " \"@type\": \"type.googleapis.com/google.protobuf.Value\",\n" + " \"value\": 1.125\n" + " },\n" + " \"any_value_number\": {\n" + " \"@type\": \"type.googleapis.com/google.protobuf.Any\",\n" + " \"value\": {\n" + " \"@type\": \"type.googleapis.com/google.protobuf.Value\",\n" + " \"value\": 1.125\n" + " }\n" + " },\n" + " \"any_value_default\": {\n" + " \"@type\": \"type.googleapis.com/google.protobuf.Any\",\n" + " \"value\": {}\n" + " },\n" + " \"default\": {}\n" + " }\n" + "}", printer.print(testAny.build())); assertRoundTripEquals(testAny.build(), registry); }