18 changed files with 725 additions and 738 deletions
@ -1,50 +0,0 @@ |
|||||
/** |
|
||||
* Copyright © 2016-2020 The Thingsboard Authors |
|
||||
* |
|
||||
* 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 org.thingsboard.server.common.data.device.profile; |
|
||||
|
|
||||
import com.fasterxml.jackson.core.JsonParser; |
|
||||
import com.fasterxml.jackson.core.JsonProcessingException; |
|
||||
import com.fasterxml.jackson.databind.DeserializationContext; |
|
||||
import com.fasterxml.jackson.databind.JsonNode; |
|
||||
import com.fasterxml.jackson.databind.deser.std.StdDeserializer; |
|
||||
import lombok.extern.slf4j.Slf4j; |
|
||||
import org.thingsboard.server.common.data.TransportPayloadType; |
|
||||
|
|
||||
import java.io.IOException; |
|
||||
|
|
||||
@Slf4j |
|
||||
public class MqttTransportConfigurationDeserializer extends StdDeserializer<MqttDeviceProfileTransportConfiguration> { |
|
||||
|
|
||||
public MqttTransportConfigurationDeserializer() { |
|
||||
super(MqttDeviceProfileTransportConfiguration.class); |
|
||||
} |
|
||||
|
|
||||
@Override |
|
||||
public MqttDeviceProfileTransportConfiguration deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JsonProcessingException { |
|
||||
try { |
|
||||
JsonNode jsonNode = jsonParser.readValueAsTree(); |
|
||||
if (jsonNode.hasNonNull("transportPayloadType") && jsonNode.get("transportPayloadType").asText().equals(TransportPayloadType.PROTOBUF.name())) { |
|
||||
return jsonParser.getCodec().treeToValue(jsonNode, MqttProtoDeviceProfileTransportConfiguration.class); |
|
||||
} else { |
|
||||
return jsonParser.getCodec().treeToValue(jsonNode, MqttJsonDeviceProfileTransportConfiguration.class); |
|
||||
} |
|
||||
} catch (IOException e) { |
|
||||
log.trace("Failed to deserialize JSON content into equivalent tree model during creating {}!", MqttDeviceProfileTransportConfiguration.class.getSimpleName(), e); |
|
||||
throw new RuntimeException("Failed to deserialize JSON content into equivalent tree model during creating " + MqttDeviceProfileTransportConfiguration.class.getSimpleName() + "!", e); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
} |
|
||||
@ -0,0 +1,37 @@ |
|||||
|
/** |
||||
|
* Copyright © 2016-2020 The Thingsboard Authors |
||||
|
* |
||||
|
* 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 org.thingsboard.server.common.data.device.profile; |
||||
|
|
||||
|
import com.fasterxml.jackson.annotation.JsonIgnore; |
||||
|
import com.fasterxml.jackson.annotation.JsonIgnoreProperties; |
||||
|
import com.fasterxml.jackson.annotation.JsonSubTypes; |
||||
|
import com.fasterxml.jackson.annotation.JsonTypeInfo; |
||||
|
import org.thingsboard.server.common.data.TransportPayloadType; |
||||
|
|
||||
|
@JsonIgnoreProperties(ignoreUnknown = true) |
||||
|
@JsonTypeInfo( |
||||
|
use = JsonTypeInfo.Id.NAME, |
||||
|
include = JsonTypeInfo.As.PROPERTY, |
||||
|
property = "transportPayloadType") |
||||
|
@JsonSubTypes({ |
||||
|
@JsonSubTypes.Type(value = JsonTransportPayloadConfiguration.class, name = "JSON"), |
||||
|
@JsonSubTypes.Type(value = ProtoTransportPayloadConfiguration.class, name = "PROTOBUF")}) |
||||
|
public interface TransportPayloadTypeConfiguration { |
||||
|
|
||||
|
@JsonIgnore |
||||
|
TransportPayloadType getTransportPayloadType(); |
||||
|
|
||||
|
} |
||||
@ -1,406 +0,0 @@ |
|||||
/** |
|
||||
* Copyright © 2016-2020 The Thingsboard Authors |
|
||||
* |
|
||||
* 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 org.thingsboard.server.transport.mqtt.util; |
|
||||
|
|
||||
import com.github.os72.protobuf.dynamic.DynamicSchema; |
|
||||
import com.google.protobuf.Descriptors; |
|
||||
import com.google.protobuf.DynamicMessage; |
|
||||
import com.google.protobuf.InvalidProtocolBufferException; |
|
||||
import com.google.protobuf.util.JsonFormat; |
|
||||
import com.squareup.wire.schema.internal.parser.ProtoFileElement; |
|
||||
import com.squareup.wire.schema.internal.parser.ProtoParser; |
|
||||
import org.junit.Rule; |
|
||||
import org.junit.Test; |
|
||||
import org.junit.rules.ExpectedException; |
|
||||
import org.junit.runner.RunWith; |
|
||||
import org.mockito.runners.MockitoJUnitRunner; |
|
||||
import org.thingsboard.server.common.data.device.profile.MqttProtoDeviceProfileTransportConfiguration; |
|
||||
|
|
||||
import java.util.List; |
|
||||
import java.util.Set; |
|
||||
|
|
||||
import static org.junit.Assert.assertEquals; |
|
||||
import static org.junit.Assert.assertNotNull; |
|
||||
import static org.junit.Assert.assertTrue; |
|
||||
import static org.thingsboard.server.common.data.device.profile.MqttProtoDeviceProfileTransportConfiguration.LOCATION; |
|
||||
|
|
||||
@RunWith(MockitoJUnitRunner.class) |
|
||||
public class MqttDynamicProtoSchemaTest { |
|
||||
|
|
||||
private static final String PROTO_SCHEMA_WITH_NESTED_MSG_TYPES = "syntax = \"proto3\";\n" + |
|
||||
"\n" + |
|
||||
"package testnested;\n" + |
|
||||
"\n" + |
|
||||
"message Outer {\n" + |
|
||||
" message MiddleAA {\n" + |
|
||||
" message Inner {\n" + |
|
||||
" int64 ival = 1;\n" + |
|
||||
" bool booly = 2;\n" + |
|
||||
" }\n" + |
|
||||
" Inner inner = 1;\n" + |
|
||||
" }\n" + |
|
||||
" message MiddleBB {\n" + |
|
||||
" message Inner {\n" + |
|
||||
" int32 ival = 1;\n" + |
|
||||
" bool booly = 2;\n" + |
|
||||
" }\n" + |
|
||||
" Inner inner = 1;\n" + |
|
||||
" }\n" + |
|
||||
" MiddleAA middleAA = 1;\n" + |
|
||||
" MiddleBB middleBB = 2;\n" + |
|
||||
"}\n"; |
|
||||
|
|
||||
private static final String PROTO_SCHEMA_WITH_ONE_OFS = "syntax = \"proto3\";\n" + |
|
||||
"\n" + |
|
||||
"package testoneofs;\n" + |
|
||||
"\n" + |
|
||||
"message SubMessage {\n" + |
|
||||
" repeated string name = 1;\n" + |
|
||||
"}\n" + |
|
||||
"\n" + |
|
||||
"message SampleMessage {\n" + |
|
||||
" oneof testOneOf {\n" + |
|
||||
" string name = 4;\n" + |
|
||||
" SubMessage subMessage = 9;\n" + |
|
||||
" }\n" + |
|
||||
"}"; |
|
||||
|
|
||||
private static final String IVALID_PROTO_SCHEMA_REQUIRED_FIELD_EXISTS = "syntax = \"proto3\";\n" + |
|
||||
"\n" + |
|
||||
"package schemavalidation;\n" + |
|
||||
"\n" + |
|
||||
"message SchemaValidationTest {\n" + |
|
||||
" required int32 parameter = 1;\n" + |
|
||||
"}"; |
|
||||
|
|
||||
private static final String INVALID_PROTO_SCHEMA_NOT_VALID_SYNTAX = "syntax = \"proto2\";\n" + |
|
||||
"\n" + |
|
||||
"package schemavalidation;\n" + |
|
||||
"\n" + |
|
||||
"message SchemaValidationTest {\n" + |
|
||||
" required int32 parameter = 1;\n" + |
|
||||
"}"; |
|
||||
|
|
||||
private static final String INVALID_PROTO_SCHEMA_OPTIONS_NOT_SUPPORTED = "syntax = \"proto3\";\n" + |
|
||||
"\n" + |
|
||||
"option java_package = \"com.test.schemavalidation\";\n" + |
|
||||
"option java_multiple_files = true;\n" + |
|
||||
"\n" + |
|
||||
"package schemavalidation;\n" + |
|
||||
"\n" + |
|
||||
"message SchemaValidationTest {\n" + |
|
||||
" int32 parameter = 1;\n" + |
|
||||
"}"; |
|
||||
|
|
||||
private static final String INVALID_PROTO_SCHEMA_PUBLIC_IMPORTS_NOT_SUPPORTED = "syntax = \"proto3\";\n" + |
|
||||
"\n" + |
|
||||
"import public \"oldschema.proto\";\n" + |
|
||||
"\n" + |
|
||||
"package schemavalidation;\n" + |
|
||||
"\n" + |
|
||||
"message SchemaValidationTest {\n" + |
|
||||
" int32 parameter = 1;\n" + |
|
||||
"}"; |
|
||||
|
|
||||
private static final String INVALID_PROTO_SCHEMA_IMPORTS_NOT_SUPPORTED = "syntax = \"proto3\";\n" + |
|
||||
"\n" + |
|
||||
"import \"oldschema.proto\";\n" + |
|
||||
"\n" + |
|
||||
"package schemavalidation;\n" + |
|
||||
"\n" + |
|
||||
"message SchemaValidationTest {\n" + |
|
||||
" int32 parameter = 1;\n" + |
|
||||
"}"; |
|
||||
|
|
||||
private static final String INVALID_PROTO_SCHEMA_EXTEND_DECLARATION_NOT_SUPPORTED = "syntax = \"proto3\";\n" + |
|
||||
"\n" + |
|
||||
"package schemavalidation;\n" + |
|
||||
"\n" + |
|
||||
"extend google.protobuf.MethodOptions {\n" + |
|
||||
" MyMessage my_method_option = 50007;\n" + |
|
||||
"}"; |
|
||||
|
|
||||
private static final String INVALID_PROTO_SCHEMA_ENUM_OPTIONS_NOT_SUPPORTED = "syntax = \"proto3\";\n" + |
|
||||
"\n" + |
|
||||
"package schemavalidation;\n" + |
|
||||
"\n" + |
|
||||
"enum testEnum {\n" + |
|
||||
" option allow_alias = true;\n" + |
|
||||
" DEFAULT = 0;\n" + |
|
||||
" STARTED = 1;\n" + |
|
||||
" RUNNING = 2;\n" + |
|
||||
"}\n" + |
|
||||
"\n" + |
|
||||
"message testMessage {\n" + |
|
||||
" int32 parameter = 1;\n" + |
|
||||
"}\n"; |
|
||||
|
|
||||
private static final String INVALID_PROTO_SCHEMA_NO_MESSAGE_TYPES_EXISTS = "syntax = \"proto3\";\n" + |
|
||||
"\n" + |
|
||||
"package schemavalidation;\n" + |
|
||||
"\n" + |
|
||||
"enum testEnum {\n" + |
|
||||
" DEFAULT = 0;\n" + |
|
||||
" STARTED = 1;\n" + |
|
||||
" RUNNING = 2;\n" + |
|
||||
"}"; |
|
||||
|
|
||||
private static final String INVALID_PROTO_SCHEMA_MESSAGE_OPTIONS_NOT_SUPPORTED = "syntax = \"proto3\";\n" + |
|
||||
"\n" + |
|
||||
"package schemavalidation;\n" + |
|
||||
"\n" + |
|
||||
"message testMessage {\n" + |
|
||||
" option allow_alias = true;\n" + |
|
||||
" int32 parameter = 1;\n" + |
|
||||
"}"; |
|
||||
|
|
||||
private static final String INVALID_PROTO_SCHEMA_MESSAGE_EXTENSIONS_NOT_SUPPORTED = "syntax = \"proto3\";\n" + |
|
||||
"\n" + |
|
||||
"package schemavalidation;\n" + |
|
||||
"\n" + |
|
||||
"message TestMessage {\n" + |
|
||||
" extensions 100 to 199;\n" + |
|
||||
"}\n"; |
|
||||
|
|
||||
private static final String INVALID_PROTO_SCHEMA_MESSAGE_GROUPS_NOT_SUPPORTED = "syntax = \"proto3\";\n" + |
|
||||
"\n" + |
|
||||
"package schemavalidation;\n" + |
|
||||
"\n" + |
|
||||
"message TestMessage {\n" + |
|
||||
" repeated group Result = 1 {\n" + |
|
||||
" string url = 2;\n" + |
|
||||
" string title = 3;\n" + |
|
||||
" repeated string snippets = 4;\n" + |
|
||||
" }\n" + |
|
||||
"}\n"; |
|
||||
|
|
||||
private static final String INVALID_PROTO_SCHEMA_MESSAGE_RESERVED_NOT_SUPPORTED = "syntax = \"proto3\";\n" + |
|
||||
"\n" + |
|
||||
"package schemavalidation;\n" + |
|
||||
"\n" + |
|
||||
"message Foo {\n" + |
|
||||
" reserved 2, 15, 9 to 11;\n" + |
|
||||
" reserved \"foo\", \"bar\";\n" + |
|
||||
"}"; |
|
||||
|
|
||||
private static final String INVALID_PROTO_SCHEMA_ONE_OFS_GROUPS_NOT_SUPPORTED = "syntax = \"proto3\";\n" + |
|
||||
"\n" + |
|
||||
"package schemavalidation;\n" + |
|
||||
"\n" + |
|
||||
"message SampleMessage {\n" + |
|
||||
" oneof test_oneof {\n" + |
|
||||
" string name = 1;\n" + |
|
||||
" group Result = 2 {\n" + |
|
||||
" \tstring url = 3;\n" + |
|
||||
" \tstring title = 4;\n" + |
|
||||
" \trepeated string snippets = 5;\n" + |
|
||||
" }\n" + |
|
||||
" }\n" + |
|
||||
"}"; |
|
||||
|
|
||||
private static final MqttProtoDeviceProfileTransportConfiguration mqttProtoDeviceProfileTransportConfiguration = new MqttProtoDeviceProfileTransportConfiguration(); |
|
||||
|
|
||||
private static void validateTransportProtoSchema(String schema, String schemaName) { |
|
||||
mqttProtoDeviceProfileTransportConfiguration.validateTransportProtoSchema(schema, schemaName); |
|
||||
} |
|
||||
|
|
||||
private static DynamicSchema getDynamicSchema(String schema, String schemaName) { |
|
||||
ProtoFileElement protoFileElement = getTransportProtoSchema(schema); |
|
||||
return mqttProtoDeviceProfileTransportConfiguration.getDynamicSchema(protoFileElement, schemaName); |
|
||||
} |
|
||||
|
|
||||
@Rule |
|
||||
public ExpectedException exceptionRule = ExpectedException.none(); |
|
||||
|
|
||||
@Test |
|
||||
public void testDynamicSchemaProtoFileValidation() { |
|
||||
processValidation("[Transport Configuration] failed to parse testParseToProtoFile due to: Syntax error in :6:4: 'required' label forbidden in proto3 field declarations", IVALID_PROTO_SCHEMA_REQUIRED_FIELD_EXISTS, "testParseToProtoFile"); |
|
||||
} |
|
||||
|
|
||||
@Test |
|
||||
public void testDynamicSchemaSyntaxValidation() { |
|
||||
processValidation("[Transport Configuration] invalid schema syntax: proto2 for: testSyntaxValidation provided! Only proto3 allowed!", INVALID_PROTO_SCHEMA_NOT_VALID_SYNTAX, "testSyntaxValidation"); |
|
||||
} |
|
||||
|
|
||||
@Test |
|
||||
public void testDynamicSchemaOptionsValidation() { |
|
||||
processValidation("[Transport Configuration] invalid testOptionsValidation schema provided! Schema options don't support!", INVALID_PROTO_SCHEMA_OPTIONS_NOT_SUPPORTED, "testOptionsValidation"); |
|
||||
} |
|
||||
|
|
||||
@Test |
|
||||
public void testDynamicSchemaPublicImportsValidation() { |
|
||||
processValidation("[Transport Configuration] invalid testPublicImportsValidation schema provided! Schema public imports don't support!", INVALID_PROTO_SCHEMA_PUBLIC_IMPORTS_NOT_SUPPORTED, "testPublicImportsValidation"); |
|
||||
} |
|
||||
|
|
||||
@Test |
|
||||
public void testDynamicSchemaImportsValidation() { |
|
||||
processValidation("[Transport Configuration] invalid testImportsValidation schema provided! Schema imports don't support!", INVALID_PROTO_SCHEMA_IMPORTS_NOT_SUPPORTED, "testImportsValidation"); |
|
||||
} |
|
||||
|
|
||||
@Test |
|
||||
public void testDynamicSchemaExtendDeclarationsValidation() { |
|
||||
processValidation("[Transport Configuration] invalid testExtendDeclarationsValidation schema provided! Schema extend declarations don't support!", INVALID_PROTO_SCHEMA_EXTEND_DECLARATION_NOT_SUPPORTED, "testExtendDeclarationsValidation"); |
|
||||
} |
|
||||
|
|
||||
@Test |
|
||||
public void testDynamicSchemaEnumOptionsValidation() { |
|
||||
processValidation("[Transport Configuration] invalid testEnumOptionsValidation schema provided! Enum definitions options are not supported!", INVALID_PROTO_SCHEMA_ENUM_OPTIONS_NOT_SUPPORTED, "testEnumOptionsValidation"); |
|
||||
} |
|
||||
|
|
||||
@Test |
|
||||
public void testDynamicSchemaNoOneMessageTypeExistsValidation() { |
|
||||
processValidation("[Transport Configuration] invalid noOneMessageTypeExists schema provided! At least one Message definition should exists!", INVALID_PROTO_SCHEMA_NO_MESSAGE_TYPES_EXISTS, "noOneMessageTypeExists"); |
|
||||
} |
|
||||
|
|
||||
@Test |
|
||||
public void testDynamicSchemaMessageTypeOptionsValidation() { |
|
||||
processValidation("[Transport Configuration] invalid messageTypeOptions schema provided! Message definition options don't support!", INVALID_PROTO_SCHEMA_MESSAGE_OPTIONS_NOT_SUPPORTED, "messageTypeOptions"); |
|
||||
} |
|
||||
|
|
||||
@Test |
|
||||
public void testDynamicSchemaMessageTypeExtensionsValidation() { |
|
||||
processValidation("[Transport Configuration] invalid messageTypeExtensions schema provided! Message definition extensions don't support!", INVALID_PROTO_SCHEMA_MESSAGE_EXTENSIONS_NOT_SUPPORTED, "messageTypeExtensions"); |
|
||||
} |
|
||||
|
|
||||
@Test |
|
||||
public void testDynamicSchemaMessageTypeReservedElementsValidation() { |
|
||||
processValidation("[Transport Configuration] invalid messageTypeReservedElements schema provided! Message definition reserved elements don't support!", INVALID_PROTO_SCHEMA_MESSAGE_RESERVED_NOT_SUPPORTED, "messageTypeReservedElements"); |
|
||||
} |
|
||||
|
|
||||
@Test |
|
||||
public void testDynamicSchemaMessageTypeGroupsElementsValidation() { |
|
||||
processValidation("[Transport Configuration] invalid messageTypeGroupsElements schema provided! Message definition groups don't support!", INVALID_PROTO_SCHEMA_MESSAGE_GROUPS_NOT_SUPPORTED, "messageTypeGroupsElements"); |
|
||||
} |
|
||||
|
|
||||
@Test |
|
||||
public void testDynamicSchemaOneOfsTypeGroupsElementsValidation() { |
|
||||
processValidation("[Transport Configuration] invalid oneOfsTypeGroupsElements schema provided! OneOf definition groups don't support!", INVALID_PROTO_SCHEMA_ONE_OFS_GROUPS_NOT_SUPPORTED, "oneOfsTypeGroupsElements"); |
|
||||
} |
|
||||
|
|
||||
private void processValidation(String expectedMessage, String schema, String schemaName) { |
|
||||
exceptionRule.expect(IllegalArgumentException.class); |
|
||||
exceptionRule.expectMessage(expectedMessage); |
|
||||
validateTransportProtoSchema(schema, schemaName); |
|
||||
} |
|
||||
|
|
||||
@Test |
|
||||
public void testDynamicSchemaCreationWithMessageNestedTypes() throws Exception { |
|
||||
String testNestedTypesProtoSchema = "testNestedTypesProtoSchema"; |
|
||||
validateTransportProtoSchema(PROTO_SCHEMA_WITH_NESTED_MSG_TYPES, testNestedTypesProtoSchema); |
|
||||
DynamicSchema dynamicSchema = getDynamicSchema(PROTO_SCHEMA_WITH_NESTED_MSG_TYPES, testNestedTypesProtoSchema); |
|
||||
assertNotNull(dynamicSchema); |
|
||||
Set<String> messageTypes = dynamicSchema.getMessageTypes(); |
|
||||
assertEquals(5, messageTypes.size()); |
|
||||
assertTrue(messageTypes.contains("testnested.Outer")); |
|
||||
assertTrue(messageTypes.contains("testnested.Outer.MiddleAA")); |
|
||||
assertTrue(messageTypes.contains("testnested.Outer.MiddleAA.Inner")); |
|
||||
assertTrue(messageTypes.contains("testnested.Outer.MiddleBB")); |
|
||||
assertTrue(messageTypes.contains("testnested.Outer.MiddleBB.Inner")); |
|
||||
|
|
||||
DynamicMessage.Builder middleAAInnerMsgBuilder = dynamicSchema.newMessageBuilder("testnested.Outer.MiddleAA.Inner"); |
|
||||
Descriptors.Descriptor middleAAInnerMsgDescriptor = middleAAInnerMsgBuilder.getDescriptorForType(); |
|
||||
DynamicMessage middleAAInnerMsg = middleAAInnerMsgBuilder |
|
||||
.setField(middleAAInnerMsgDescriptor.findFieldByName("ival"), 1L) |
|
||||
.setField(middleAAInnerMsgDescriptor.findFieldByName("booly"), true) |
|
||||
.build(); |
|
||||
|
|
||||
DynamicMessage.Builder middleAAMsgBuilder = dynamicSchema.newMessageBuilder("testnested.Outer.MiddleAA"); |
|
||||
Descriptors.Descriptor middleAAMsgDescriptor = middleAAMsgBuilder.getDescriptorForType(); |
|
||||
DynamicMessage middleAAMsg = middleAAMsgBuilder |
|
||||
.setField(middleAAMsgDescriptor.findFieldByName("inner"), middleAAInnerMsg) |
|
||||
.build(); |
|
||||
|
|
||||
DynamicMessage.Builder middleBBInnerMsgBuilder = dynamicSchema.newMessageBuilder("testnested.Outer.MiddleAA.Inner"); |
|
||||
Descriptors.Descriptor middleBBInnerMsgDescriptor = middleBBInnerMsgBuilder.getDescriptorForType(); |
|
||||
DynamicMessage middleBBInnerMsg = middleBBInnerMsgBuilder |
|
||||
.setField(middleBBInnerMsgDescriptor.findFieldByName("ival"), 0L) |
|
||||
.setField(middleBBInnerMsgDescriptor.findFieldByName("booly"), false) |
|
||||
.build(); |
|
||||
|
|
||||
DynamicMessage.Builder middleBBMsgBuilder = dynamicSchema.newMessageBuilder("testnested.Outer.MiddleBB"); |
|
||||
Descriptors.Descriptor middleBBMsgDescriptor = middleBBMsgBuilder.getDescriptorForType(); |
|
||||
DynamicMessage middleBBMsg = middleBBMsgBuilder |
|
||||
.setField(middleBBMsgDescriptor.findFieldByName("inner"), middleBBInnerMsg) |
|
||||
.build(); |
|
||||
|
|
||||
|
|
||||
DynamicMessage.Builder outerMsgBuilder = dynamicSchema.newMessageBuilder("testnested.Outer"); |
|
||||
Descriptors.Descriptor outerMsgBuilderDescriptor = outerMsgBuilder.getDescriptorForType(); |
|
||||
DynamicMessage outerMsg = outerMsgBuilder |
|
||||
.setField(outerMsgBuilderDescriptor.findFieldByName("middleAA"), middleAAMsg) |
|
||||
.setField(outerMsgBuilderDescriptor.findFieldByName("middleBB"), middleBBMsg) |
|
||||
.build(); |
|
||||
|
|
||||
assertEquals("{\n" + |
|
||||
" \"middleAA\": {\n" + |
|
||||
" \"inner\": {\n" + |
|
||||
" \"ival\": \"1\",\n" + |
|
||||
" \"booly\": true\n" + |
|
||||
" }\n" + |
|
||||
" },\n" + |
|
||||
" \"middleBB\": {\n" + |
|
||||
" \"inner\": {\n" + |
|
||||
" \"ival\": 0,\n" + |
|
||||
" \"booly\": false\n" + |
|
||||
" }\n" + |
|
||||
" }\n" + |
|
||||
"}", dynamicMsgToJson(outerMsgBuilderDescriptor, outerMsg.toByteArray())); |
|
||||
} |
|
||||
|
|
||||
@Test |
|
||||
public void testDynamicSchemaCreationWithMessageOneOfs() throws Exception { |
|
||||
String testOneOfsProtoSchema = "testOneOfsProtoSchema"; |
|
||||
validateTransportProtoSchema(PROTO_SCHEMA_WITH_ONE_OFS, testOneOfsProtoSchema); |
|
||||
DynamicSchema dynamicSchema = getDynamicSchema(PROTO_SCHEMA_WITH_ONE_OFS, testOneOfsProtoSchema); |
|
||||
assertNotNull(dynamicSchema); |
|
||||
Set<String> messageTypes = dynamicSchema.getMessageTypes(); |
|
||||
assertEquals(2, messageTypes.size()); |
|
||||
assertTrue(messageTypes.contains("testoneofs.SubMessage")); |
|
||||
assertTrue(messageTypes.contains("testoneofs.SampleMessage")); |
|
||||
|
|
||||
DynamicMessage.Builder sampleMsgBuilder = dynamicSchema.newMessageBuilder("testoneofs.SampleMessage"); |
|
||||
Descriptors.Descriptor sampleMsgDescriptor = sampleMsgBuilder.getDescriptorForType(); |
|
||||
assertNotNull(sampleMsgDescriptor); |
|
||||
|
|
||||
List<Descriptors.FieldDescriptor> fields = sampleMsgDescriptor.getFields(); |
|
||||
assertEquals(2, fields.size()); |
|
||||
DynamicMessage sampleMsg = sampleMsgBuilder |
|
||||
.setField(sampleMsgDescriptor.findFieldByName("name"), "Bob") |
|
||||
.build(); |
|
||||
assertEquals("{\n" + " \"name\": \"Bob\"\n" + "}", dynamicMsgToJson(sampleMsgDescriptor, sampleMsg.toByteArray())); |
|
||||
|
|
||||
DynamicMessage.Builder subMsgBuilder = dynamicSchema.newMessageBuilder("testoneofs.SubMessage"); |
|
||||
Descriptors.Descriptor subMsgDescriptor = subMsgBuilder.getDescriptorForType(); |
|
||||
DynamicMessage subMsg = subMsgBuilder |
|
||||
.addRepeatedField(subMsgDescriptor.findFieldByName("name"), "Alice") |
|
||||
.addRepeatedField(subMsgDescriptor.findFieldByName("name"), "John") |
|
||||
.build(); |
|
||||
|
|
||||
DynamicMessage sampleMsgWithOneOfSubMessage = sampleMsgBuilder.setField(sampleMsgDescriptor.findFieldByName("subMessage"), subMsg).build(); |
|
||||
assertEquals("{\n" + " \"subMessage\": {\n" + " \"name\": [\"Alice\", \"John\"]\n" + " }\n" + "}", |
|
||||
dynamicMsgToJson(sampleMsgDescriptor, sampleMsgWithOneOfSubMessage.toByteArray())); |
|
||||
|
|
||||
} |
|
||||
|
|
||||
private String dynamicMsgToJson(Descriptors.Descriptor descriptor, byte[] payload) throws InvalidProtocolBufferException { |
|
||||
DynamicMessage dynamicMessage = DynamicMessage.parseFrom(descriptor, payload); |
|
||||
return JsonFormat.printer().includingDefaultValueFields().print(dynamicMessage); |
|
||||
} |
|
||||
|
|
||||
private static ProtoFileElement getTransportProtoSchema(String protoSchema) { |
|
||||
return new ProtoParser(LOCATION, protoSchema.toCharArray()).readProtoFile(); |
|
||||
} |
|
||||
} |
|
||||
Loading…
Reference in new issue