• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2022 Google LLC
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package com.google.android.libraries.mobiledatadownload.file.openers;
17 
18 import com.google.android.libraries.mobiledatadownload.file.OpenContext;
19 import com.google.android.libraries.mobiledatadownload.file.Opener;
20 import com.google.errorprone.annotations.CanIgnoreReturnValue;
21 import com.google.protobuf.ExtensionRegistryLite;
22 import com.google.protobuf.MessageLite;
23 import com.google.protobuf.Parser;
24 import java.io.IOException;
25 import java.io.InputStream;
26 
27 /**
28  * Opener for reading Protocol Buffers from file. It is based on the Java Proto Lite implementation;
29  * see <internal> for more information. Note that this opener reads the entire stream into a single
30  * message, meaning that delimited files are not supported. If the byte contents of the Uri cannot
31  * be parsed as a valid protocol message, throws {@link InvalidProtocolBufferException}.
32  *
33  * <p>Usage: <code>
34  * MyProto proto = storage.open(uri, ReadProtoOpener.create(MyProto.parser()));
35  * </code>
36  *
37  * <p>TODO(b/75909287): consider adding alternative implementation for multi-proto files
38  */
39 public final class ReadProtoOpener<T extends MessageLite> implements Opener<T> {
40 
41   private final Parser<T> parser;
42   private ExtensionRegistryLite registry = ExtensionRegistryLite.getEmptyRegistry();
43 
ReadProtoOpener(Parser<T> parser)44   private ReadProtoOpener(Parser<T> parser) {
45     this.parser = parser;
46   }
47 
48   /** Creates a new opener instance that reads protos using the given {@code parser}. */
create(Parser<T> parser)49   public static <T extends MessageLite> ReadProtoOpener<T> create(Parser<T> parser) {
50     return new ReadProtoOpener<T>(parser);
51   }
52 
53   /**
54    * Creates a new opener instance that reads protos using the parser of the given {@code message}.
55    * This can be useful if the type of T is unavailable at compile time (i.e. it's a generic).
56    */
create(T message)57   public static <T extends MessageLite> ReadProtoOpener<T> create(T message) {
58     @SuppressWarnings("unchecked") // safe cast because getParserForType API must return a Parser<T>
59     Parser<T> parser = (Parser<T>) message.getParserForType();
60     return new ReadProtoOpener<T>(parser);
61   }
62 
63   /** Adds an extension registry used while parsing the proto. */
64   @CanIgnoreReturnValue
withExtensionRegistry(ExtensionRegistryLite registry)65   public ReadProtoOpener<T> withExtensionRegistry(ExtensionRegistryLite registry) {
66     this.registry = registry;
67     return this;
68   }
69 
70   @Override
open(OpenContext openContext)71   public T open(OpenContext openContext) throws IOException {
72     try (InputStream in = ReadStreamOpener.create().open(openContext)) {
73       return parser.parseFrom(in, registry);
74     }
75   }
76 }
77