private FileDescriptorProto generateFile(String name, FileContents contents) { FileDescriptorProto.Builder fileBuilder = FileDescriptorProto.newBuilder(); fileBuilder.setName(name); if (!Strings.isNullOrEmpty(contents.packageName)) { fileBuilder.setPackage(contents.packageName); } for (Api api : contents.apis) { fileBuilder.addService(generateApi(api)); } for (Type type : contents.types.values()) { fileBuilder.addMessageType(generateType(type, contents)); } for (Enum e : contents.enums) { fileBuilder.addEnumType(generateEnum(e)); } if (imports.containsKey(name)) { for (String imported : imports.get(name)) { fileBuilder.addDependency(imported); } } return fileBuilder.build(); }
/** Create the {@link Type} with given fields. */ private void addTypeFromFields( Service.Builder serviceBuilder, String typeFullName, Iterable<Field> fields, Iterable<Option> options) { Type.Builder coreTypeBuilder = Type.newBuilder().setName(typeFullName); coreTypeBuilder.getSourceContextBuilder().setFileName(namespace); coreTypeBuilder.addAllFields(fields); coreTypeBuilder.setSyntax(Syntax.SYNTAX_PROTO3); if (options != null) { coreTypeBuilder.addAllOptions(options); } createdTypesFullName.add(coreTypeBuilder.getName()); Type coreType = coreTypeBuilder.build(); if (!serviceBuilder.getTypesList().contains(coreType)) { serviceBuilder.addTypes(coreTypeBuilder.build()); } }
@Test public void testJsonIoException() throws Exception { Marshaller<Type> marshaller = ProtoUtils.jsonMarshaller(Type.getDefaultInstance()); final IOException ioe = new IOException(); try { marshaller.parse(new ByteArrayInputStream("{}".getBytes("UTF-8")) { @Override public void close() throws IOException { throw ioe; } }); fail("Exception expected"); } catch (StatusRuntimeException ex) { assertEquals(Status.Code.INTERNAL, ex.getStatus().getCode()); assertEquals(ioe, ex.getCause()); } }
/** In proto3, repeated fields of scalar numeric types use packed encoding by default */ private boolean isDefaultPackedEncoding(Field field) { if (field.getSyntax() == Syntax.SYNTAX_PROTO3 && field.isRepeated()) { FieldDescriptorProto.Type fieldType = field.getProto().getType(); if (fieldType != FieldDescriptorProto.Type.TYPE_GROUP && fieldType != FieldDescriptorProto.Type.TYPE_BYTES && fieldType != FieldDescriptorProto.Type.TYPE_STRING && fieldType != FieldDescriptorProto.Type.TYPE_MESSAGE) { return true; } } return false; }
/** * Creates additional types (Value, Struct and ListValue) 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<Type> createAdditionalServiceTypes() { Map<String, DescriptorProto> additionalMessages = Maps.newHashMap(); additionalMessages.put(Struct.getDescriptor().getFullName(), Struct.getDescriptor().toProto()); additionalMessages.put(Value.getDescriptor().getFullName(), Value.getDescriptor().toProto()); additionalMessages.put(ListValue.getDescriptor().getFullName(), ListValue.getDescriptor().toProto()); additionalMessages.put(Empty.getDescriptor().getFullName(), Empty.getDescriptor().toProto()); additionalMessages.put(Int32Value.getDescriptor().getFullName(), Int32Value.getDescriptor().toProto()); additionalMessages.put(DoubleValue.getDescriptor().getFullName(), DoubleValue.getDescriptor().toProto()); additionalMessages.put(BoolValue.getDescriptor().getFullName(), BoolValue.getDescriptor().toProto()); additionalMessages.put(StringValue.getDescriptor().getFullName(), StringValue.getDescriptor().toProto()); for (Descriptor descriptor : Struct.getDescriptor().getNestedTypes()) { additionalMessages.put(descriptor.getFullName(), descriptor.toProto()); } // TODO (guptasu): Remove this hard coding. Without this, creation of Model from Service throws. // Needs investigation. String fileName = "struct.proto"; List<Type> additionalTypes = Lists.newArrayList(); for (String typeName : additionalMessages.keySet()) { additionalTypes.add(TypesBuilderFromDescriptor.createType(typeName, additionalMessages.get(typeName), fileName)); } return additionalTypes; }
/** * TODO (guptasu): only needed to create hard coded Types (Struct, ListValue, and Value). Check * if this can be removed. Create the Protobuf.Type instance from descriptorProto. */ private static Type createType(String typeName, DescriptorProto descriptorProto, String fileName) { Type.Builder coreTypeBuilder = Type.newBuilder().setName(typeName); int count = 1; for (FieldDescriptorProto fieldProto : descriptorProto.getFieldList()) { Field.Kind fieldKind = Field.Kind.valueOf(fieldProto.getType().getNumber()); Cardinality cardinality = Cardinality.CARDINALITY_OPTIONAL; if (fieldProto.getLabel() == Label.LABEL_REPEATED) { cardinality = Cardinality.CARDINALITY_REPEATED; } Field.Builder coreFieldBuilder = Field .newBuilder() .setName(fieldProto.getName()) .setNumber(count++) .setKind(fieldKind) .setCardinality(cardinality); if (fieldKind == Kind.TYPE_MESSAGE || fieldKind == Kind.TYPE_ENUM) { String typeFullName = fieldProto.getTypeName().startsWith(".") ? fieldProto.getTypeName().substring(1) : fieldProto.getTypeName(); coreFieldBuilder.setTypeUrl(TYPE_SERVICE_BASE_URL + typeFullName); } coreTypeBuilder.addFields(coreFieldBuilder.build()); } coreTypeBuilder.setSourceContext(SourceContext.newBuilder().setFileName(fileName)); coreTypeBuilder.setSyntax(Syntax.SYNTAX_PROTO3); return coreTypeBuilder.build(); }
@Test public void testRoundtrip() throws Exception { Marshaller<Type> marshaller = ProtoUtils.marshaller(Type.getDefaultInstance()); InputStream is = marshaller.stream(proto); is = new ByteArrayInputStream(ByteStreams.toByteArray(is)); assertEquals(proto, marshaller.parse(is)); }
@Test public void testJsonRoundtrip() throws Exception { Marshaller<Type> marshaller = ProtoUtils.jsonMarshaller(Type.getDefaultInstance()); InputStream is = marshaller.stream(proto); is = new ByteArrayInputStream(ByteStreams.toByteArray(is)); assertEquals(proto, marshaller.parse(is)); }
@Test public void testJsonRepresentation() throws Exception { Marshaller<Type> marshaller = ProtoUtils.jsonMarshaller(Type.getDefaultInstance()); InputStream is = marshaller.stream(proto); String s = new String(ByteStreams.toByteArray(is), "UTF-8"); assertEquals("{\"name\":\"value\"}", s.replaceAll("\\s", "")); }
@Ignore("https://github.com/google/protobuf/issues/1470") @Test public void testJsonInvalid() throws Exception { Marshaller<Type> marshaller = ProtoUtils.jsonMarshaller(Type.getDefaultInstance()); try { marshaller.parse(new ByteArrayInputStream("{]".getBytes("UTF-8"))); fail("Expected exception"); } catch (StatusRuntimeException ex) { assertEquals(Status.Code.INTERNAL, ex.getStatus().getCode()); assertNotNull(ex.getCause()); } }
@Test public void testJsonInvalidProto() throws Exception { Marshaller<Type> marshaller = ProtoUtils.jsonMarshaller(Type.getDefaultInstance()); try { marshaller.parse(new ByteArrayInputStream("{\"\":3}".getBytes("UTF-8"))); fail("Expected exception"); } catch (StatusRuntimeException ex) { assertEquals(Status.Code.INTERNAL, ex.getStatus().getCode()); assertNotNull(ex.getCause()); } }
@Test public void testInvalidatedMessage() throws Exception { InputStream is = marshaller.stream(proto); // Invalidates message, and drains all bytes byte[] unused = ByteStreams.toByteArray(is); try { ((ProtoInputStream) is).message(); fail("Expected exception"); } catch (IllegalStateException ex) { // expected } // Zero bytes is the default message assertEquals(Type.getDefaultInstance(), marshaller.parse(is)); }
@Test public void marshallerShouldNotLimitProtoSize() throws Exception { // The default limit is 64MB. Using a larger proto to verify that the limit is not enforced. byte[] bigName = new byte[70 * 1024 * 1024]; Arrays.fill(bigName, (byte) 32); proto = Type.newBuilder().setNameBytes(ByteString.copyFrom(bigName)).build(); // Just perform a round trip to verify that it works. testRoundtrip(); }
@Test public void metadataMarshaller_invalid() { Metadata.BinaryMarshaller<Type> metadataMarshaller = ProtoLiteUtils.metadataMarshaller(Type.getDefaultInstance()); try { metadataMarshaller.parseBytes(new byte[] {-127}); fail("Expected exception"); } catch (IllegalArgumentException ex) { assertNotNull(((InvalidProtocolBufferException) ex.getCause()).getUnfinishedMessage()); } }
@Test public void parseFromKnowLengthInputStream() throws Exception { Marshaller<Type> marshaller = ProtoLiteUtils.marshaller(Type.getDefaultInstance()); Type expect = Type.newBuilder().setName("expected name").build(); Type result = marshaller.parse(new CustomKnownLengthInputStream(expect.toByteArray())); assertEquals(expect, result); }
private MessageOptions generateMessageOptions(Type type) { MessageOptions.Builder builder = MessageOptions.newBuilder(); setOptions(builder, type.getOptionsList(), TYPE_OPTION_NAME_PREFIX); return builder.build(); }
private FieldDescriptorProto.Type toType(Kind kind) { return FieldDescriptorProto.Type.valueOf(kind.getNumber()); }
private <V> List<V> getOrCreateList(Map<Type, List<V>> lists, Type key) { if (!lists.containsKey(key)) { lists.put(key, Lists.<V>newArrayList()); } return lists.get(key); }
@VisitsBefore void normalize(MessageType message) { Type.Builder coreTypeBuilder = Type.newBuilder().setName(message.getFullName()); coreTypeBuilder.setSourceContext( SourceContext.newBuilder().setFileName(message.getFile().getLocation().getDisplayString())); coreTypeBuilder.setSyntax(message.getSyntax()); for (Field field : message.getReachableFields()) { com.google.protobuf.Field.Builder coreFieldBuilder = com.google.protobuf.Field.newBuilder() .setName(field.getSimpleName()) .setNumber(field.getNumber()) .setKind(toCoreFieldKind(field.getProto())) .setCardinality(toCoreFieldCardinality(field.getProto())) .setJsonName(field.getJsonName()); if (field.getType().isEnum() || field.getType().isMessage()) { coreFieldBuilder.setTypeUrl(generateTypeUrl(field.getType())); } FieldDescriptorProto proto = field.getProto(); if (proto.hasOneofIndex()) { // Index in the containing type's oneof_decl is zero-based. // Index in google.protobuf.type.Field.oneof_index is one-based. coreFieldBuilder.setOneofIndex(field.getProto().getOneofIndex() + 1); } if (proto.getOptions().hasPacked()) { coreFieldBuilder.setPacked(proto.getOptions().getPacked()); } else if (isDefaultPackedEncoding(field)) { coreFieldBuilder.setPacked(true); } if (proto.hasDefaultValue()) { coreFieldBuilder.setDefaultValue(proto.getDefaultValue()); } coreFieldBuilder.addAllOptions( DescriptorNormalization.getOptions(field.getProto(), includeDefaults)); coreTypeBuilder.addFields(coreFieldBuilder.build()); } coreTypeBuilder.addAllOptions( DescriptorNormalization.getOptions(message.getProto(), includeDefaults)); coreTypeBuilder.addAllOneofs(DescriptorNormalization.getOneofs(message.getProto())); types.add(coreTypeBuilder.build()); }
@Test public void keyForProto() { assertEquals("google.protobuf.Type-bin", ProtoUtils.keyForProto(Type.getDefaultInstance()).originalName()); }
@Test public void metadataMarshaller_roundtrip() { Metadata.BinaryMarshaller<Type> metadataMarshaller = ProtoLiteUtils.metadataMarshaller(Type.getDefaultInstance()); assertEquals(proto, metadataMarshaller.parseBytes(metadataMarshaller.toBytes(proto))); }