• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Protocol Buffers - Google's data interchange format
2 // Copyright 2008 Google Inc.  All rights reserved.
3 //
4 // Use of this source code is governed by a BSD-style
5 // license that can be found in the LICENSE file or at
6 // https://developers.google.com/open-source/licenses/bsd
7 
8 package com.google.protobuf;
9 
10 import static com.google.protobuf.Internal.checkNotNull;
11 
12 /**
13  * Dynamically generates a manifest-based (i.e. table-based) schema for a given protobuf message.
14  */
15 @CheckReturnValue
16 @ExperimentalApi
17 final class ManifestSchemaFactory implements SchemaFactory {
18 
19   private final MessageInfoFactory messageInfoFactory;
20 
ManifestSchemaFactory()21   public ManifestSchemaFactory() {
22     this(getDefaultMessageInfoFactory());
23   }
24 
ManifestSchemaFactory(MessageInfoFactory messageInfoFactory)25   private ManifestSchemaFactory(MessageInfoFactory messageInfoFactory) {
26     this.messageInfoFactory = checkNotNull(messageInfoFactory, "messageInfoFactory");
27   }
28 
29   @Override
createSchema(Class<T> messageType)30   public <T> Schema<T> createSchema(Class<T> messageType) {
31     SchemaUtil.requireGeneratedMessage(messageType);
32 
33     MessageInfo messageInfo = messageInfoFactory.messageInfoFor(messageType);
34 
35     // MessageSet has a special schema.
36     if (messageInfo.isMessageSetWireFormat()) {
37       return useLiteRuntime(messageType)
38           ? MessageSetSchema.newSchema(
39               SchemaUtil.unknownFieldSetLiteSchema(),
40               ExtensionSchemas.lite(),
41               messageInfo.getDefaultInstance())
42           : MessageSetSchema.newSchema(
43               SchemaUtil.unknownFieldSetFullSchema(),
44               ExtensionSchemas.full(),
45               messageInfo.getDefaultInstance());
46     }
47 
48     return newSchema(messageType, messageInfo);
49   }
50 
newSchema(Class<T> messageType, MessageInfo messageInfo)51   private static <T> Schema<T> newSchema(Class<T> messageType, MessageInfo messageInfo) {
52     return useLiteRuntime(messageType)
53         ? MessageSchema.newSchema(
54             messageType,
55             messageInfo,
56             NewInstanceSchemas.lite(),
57             ListFieldSchemas.lite(),
58             SchemaUtil.unknownFieldSetLiteSchema(),
59             allowExtensions(messageInfo) ? ExtensionSchemas.lite() : null,
60             MapFieldSchemas.lite())
61         : MessageSchema.newSchema(
62             messageType,
63             messageInfo,
64             NewInstanceSchemas.full(),
65             ListFieldSchemas.full(),
66             SchemaUtil.unknownFieldSetFullSchema(),
67             allowExtensions(messageInfo) ? ExtensionSchemas.full() : null,
68             MapFieldSchemas.full());
69   }
70 
allowExtensions(MessageInfo messageInfo)71   private static boolean allowExtensions(MessageInfo messageInfo) {
72     switch (messageInfo.getSyntax()) {
73       case PROTO3:
74         return false;
75       default:
76         return true;
77     }
78   }
79 
getDefaultMessageInfoFactory()80   private static MessageInfoFactory getDefaultMessageInfoFactory() {
81     return new CompositeMessageInfoFactory(
82         GeneratedMessageInfoFactory.getInstance(), getDescriptorMessageInfoFactory());
83   }
84 
85   private static class CompositeMessageInfoFactory implements MessageInfoFactory {
86     private MessageInfoFactory[] factories;
87 
CompositeMessageInfoFactory(MessageInfoFactory... factories)88     CompositeMessageInfoFactory(MessageInfoFactory... factories) {
89       this.factories = factories;
90     }
91 
92     @Override
isSupported(Class<?> clazz)93     public boolean isSupported(Class<?> clazz) {
94       for (MessageInfoFactory factory : factories) {
95         if (factory.isSupported(clazz)) {
96           return true;
97         }
98       }
99       return false;
100     }
101 
102     @Override
messageInfoFor(Class<?> clazz)103     public MessageInfo messageInfoFor(Class<?> clazz) {
104       for (MessageInfoFactory factory : factories) {
105         if (factory.isSupported(clazz)) {
106           return factory.messageInfoFor(clazz);
107         }
108       }
109       throw new UnsupportedOperationException(
110           "No factory is available for message type: " + clazz.getName());
111     }
112   }
113 
114   private static final MessageInfoFactory EMPTY_FACTORY =
115       new MessageInfoFactory() {
116         @Override
117         public boolean isSupported(Class<?> clazz) {
118           return false;
119         }
120 
121         @Override
122         public MessageInfo messageInfoFor(Class<?> clazz) {
123           throw new IllegalStateException("This should never be called.");
124         }
125       };
126 
getDescriptorMessageInfoFactory()127   private static MessageInfoFactory getDescriptorMessageInfoFactory() {
128     if (Protobuf.assumeLiteRuntime) {
129       return EMPTY_FACTORY;
130     }
131     try {
132       Class<?> clazz = Class.forName("com.google.protobuf.DescriptorMessageInfoFactory");
133       return (MessageInfoFactory) clazz.getDeclaredMethod("getInstance").invoke(null);
134     } catch (Exception e) {
135       return EMPTY_FACTORY;
136     }
137   }
138 
useLiteRuntime(Class<?> messageType)139   private static boolean useLiteRuntime(Class<?> messageType) {
140     return Protobuf.assumeLiteRuntime || GeneratedMessageLite.class.isAssignableFrom(messageType);
141   }
142 }
143