View Javadoc
1   package edu.jiangxin.apktoolbox.convert.protobuf.supervised;
2   
3   import com.google.protobuf.Descriptors;
4   import com.google.protobuf.DynamicMessage;
5   import com.google.protobuf.InvalidProtocolBufferException;
6   import com.google.protobuf.util.JsonFormat;
7   
8   import java.io.IOException;
9   import java.io.UncheckedIOException;
10  import java.nio.file.Files;
11  import java.nio.file.Path;
12  import java.util.Comparator;
13  import java.util.Objects;
14  import java.util.Optional;
15  
16  public final class ProtoToJson {
17      public static ProtoToJson fromCache(final DescriptorCache cache) {
18          Objects.requireNonNull(cache);
19  
20          return new ProtoToJson(cache);
21      }
22  
23      public static ProtoToJson fromEmptyCache() {
24          return new ProtoToJson(DescriptorCache.emptyCache());
25      }
26  
27      private final DescriptorCache cache;
28      private final JsonFormat.Printer printer = JsonFormat.printer();
29  
30      private ProtoToJson(final DescriptorCache cache) {
31          this.cache = Objects.requireNonNull(cache);
32      }
33  
34      public DescriptorCache getCache() {
35          return cache;
36      }
37  
38      public String toJson(final Path messageFile) {
39          Objects.requireNonNull(messageFile);
40  
41          try {
42              return toJson(Files.readAllBytes(messageFile), (String) null);
43          } catch (final IOException e) {
44              throw new UncheckedIOException(e);
45          }
46      }
47  
48      public String toJson(final byte[] messageRaw) {
49          Objects.requireNonNull(messageRaw);
50  
51          return toJson(messageRaw, (String) null);
52      }
53  
54      public String toJson(final Path messageFile, final String messageTypeName) {
55          Objects.requireNonNull(messageFile);
56  
57          try {
58              return toJson(Files.readAllBytes(messageFile), messageTypeName);
59          } catch (final IOException e) {
60              throw new UncheckedIOException(e);
61          }
62      }
63  
64      public String toJson(final byte[] messageRaw, final String messageTypeName) {
65          Objects.requireNonNull(messageRaw);
66  
67          if (messageTypeName == null) {
68              final Optional<DynamicMessage> message = parseWithBestMatchingDescriptor(messageRaw);
69              return toJson(message.orElseThrow(RuntimeException::new));
70          }
71  
72          final Optional<Descriptors.Descriptor> descriptor = cache.getByTypeName(messageTypeName);
73          return toJson(messageRaw, descriptor.orElseThrow(() -> new RuntimeException(messageTypeName)));
74      }
75  
76      @SuppressWarnings("WeakerAccess")
77      public String toJson(final byte[] messageRaw, final Descriptors.Descriptor descriptor) {
78          Objects.requireNonNull(messageRaw);
79          Objects.requireNonNull(descriptor);
80  
81          try {
82              return toJson(DynamicMessage.parseFrom(descriptor, messageRaw));
83          } catch (final InvalidProtocolBufferException e) {
84              throw new RuntimeException(e);
85          }
86      }
87  
88      @SuppressWarnings("WeakerAccess")
89      public String toJson(final DynamicMessage message) {
90          Objects.requireNonNull(message);
91  
92          try {
93              return printer.print(message);
94          } catch (final InvalidProtocolBufferException e) {
95              throw new RuntimeException(e);
96          }
97      }
98  
99      private Optional<DynamicMessage> parseWithBestMatchingDescriptor(final byte[] messageRaw) {
100         Objects.requireNonNull(messageRaw);
101 
102         return cache.getDescriptors()
103                 .stream()
104                 .map(descriptor -> {
105                     try {
106                         return DynamicMessage.parseFrom(descriptor, messageRaw);
107                     } catch (final InvalidProtocolBufferException e) {
108                         //noinspection ReturnOfNull
109                         return null;
110                     }
111                 })
112                 .filter(Objects::nonNull)
113                 .min(Comparator.comparingInt(message -> message.getUnknownFields()
114                         .asMap()
115                         .size()));
116     }
117 }