1 // Protocol Buffers - Google's data interchange format 2 // Copyright 2008 Google Inc. All rights reserved. 3 // https://developers.google.com/protocol-buffers/ 4 // 5 // Redistribution and use in source and binary forms, with or without 6 // modification, are permitted provided that the following conditions are 7 // met: 8 // 9 // * Redistributions of source code must retain the above copyright 10 // notice, this list of conditions and the following disclaimer. 11 // * Redistributions in binary form must reproduce the above 12 // copyright notice, this list of conditions and the following disclaimer 13 // in the documentation and/or other materials provided with the 14 // distribution. 15 // * Neither the name of Google Inc. nor the names of its 16 // contributors may be used to endorse or promote products derived from 17 // this software without specific prior written permission. 18 // 19 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 31 package com.google.protobuf; 32 33 import static com.google.protobuf.Internal.checkNotNull; 34 35 /** 36 * Dynamically generates a manifest-based (i.e. table-based) schema for a given protobuf message. 37 */ 38 @ExperimentalApi 39 final class ManifestSchemaFactory implements SchemaFactory { 40 41 private final MessageInfoFactory messageInfoFactory; 42 ManifestSchemaFactory()43 public ManifestSchemaFactory() { 44 this(getDefaultMessageInfoFactory()); 45 } 46 ManifestSchemaFactory(MessageInfoFactory messageInfoFactory)47 private ManifestSchemaFactory(MessageInfoFactory messageInfoFactory) { 48 this.messageInfoFactory = checkNotNull(messageInfoFactory, "messageInfoFactory"); 49 } 50 51 @Override createSchema(Class<T> messageType)52 public <T> Schema<T> createSchema(Class<T> messageType) { 53 SchemaUtil.requireGeneratedMessage(messageType); 54 55 MessageInfo messageInfo = messageInfoFactory.messageInfoFor(messageType); 56 57 // MessageSet has a special schema. 58 if (messageInfo.isMessageSetWireFormat()) { 59 if (GeneratedMessageLite.class.isAssignableFrom(messageType)) { 60 return MessageSetSchema.newSchema( 61 SchemaUtil.unknownFieldSetLiteSchema(), 62 ExtensionSchemas.lite(), 63 messageInfo.getDefaultInstance()); 64 } 65 return MessageSetSchema.newSchema( 66 SchemaUtil.proto2UnknownFieldSetSchema(), 67 ExtensionSchemas.full(), 68 messageInfo.getDefaultInstance()); 69 } 70 71 return newSchema(messageType, messageInfo); 72 } 73 newSchema(Class<T> messageType, MessageInfo messageInfo)74 private static <T> Schema<T> newSchema(Class<T> messageType, MessageInfo messageInfo) { 75 if (GeneratedMessageLite.class.isAssignableFrom(messageType)) { 76 return isProto2(messageInfo) 77 ? MessageSchema.newSchema( 78 messageType, 79 messageInfo, 80 NewInstanceSchemas.lite(), 81 ListFieldSchema.lite(), 82 SchemaUtil.unknownFieldSetLiteSchema(), 83 ExtensionSchemas.lite(), 84 MapFieldSchemas.lite()) 85 : MessageSchema.newSchema( 86 messageType, 87 messageInfo, 88 NewInstanceSchemas.lite(), 89 ListFieldSchema.lite(), 90 SchemaUtil.unknownFieldSetLiteSchema(), 91 /* extensionSchema= */ null, 92 MapFieldSchemas.lite()); 93 } 94 return isProto2(messageInfo) 95 ? MessageSchema.newSchema( 96 messageType, 97 messageInfo, 98 NewInstanceSchemas.full(), 99 ListFieldSchema.full(), 100 SchemaUtil.proto2UnknownFieldSetSchema(), 101 ExtensionSchemas.full(), 102 MapFieldSchemas.full()) 103 : MessageSchema.newSchema( 104 messageType, 105 messageInfo, 106 NewInstanceSchemas.full(), 107 ListFieldSchema.full(), 108 SchemaUtil.proto3UnknownFieldSetSchema(), 109 /* extensionSchema= */ null, 110 MapFieldSchemas.full()); 111 } 112 isProto2(MessageInfo messageInfo)113 private static boolean isProto2(MessageInfo messageInfo) { 114 return messageInfo.getSyntax() == ProtoSyntax.PROTO2; 115 } 116 getDefaultMessageInfoFactory()117 private static MessageInfoFactory getDefaultMessageInfoFactory() { 118 return new CompositeMessageInfoFactory( 119 GeneratedMessageInfoFactory.getInstance(), getDescriptorMessageInfoFactory()); 120 } 121 122 private static class CompositeMessageInfoFactory implements MessageInfoFactory { 123 private MessageInfoFactory[] factories; 124 CompositeMessageInfoFactory(MessageInfoFactory... factories)125 CompositeMessageInfoFactory(MessageInfoFactory... factories) { 126 this.factories = factories; 127 } 128 129 @Override isSupported(Class<?> clazz)130 public boolean isSupported(Class<?> clazz) { 131 for (MessageInfoFactory factory : factories) { 132 if (factory.isSupported(clazz)) { 133 return true; 134 } 135 } 136 return false; 137 } 138 139 @Override messageInfoFor(Class<?> clazz)140 public MessageInfo messageInfoFor(Class<?> clazz) { 141 for (MessageInfoFactory factory : factories) { 142 if (factory.isSupported(clazz)) { 143 return factory.messageInfoFor(clazz); 144 } 145 } 146 throw new UnsupportedOperationException( 147 "No factory is available for message type: " + clazz.getName()); 148 } 149 } 150 151 private static final MessageInfoFactory EMPTY_FACTORY = 152 new MessageInfoFactory() { 153 @Override 154 public boolean isSupported(Class<?> clazz) { 155 return false; 156 } 157 158 @Override 159 public MessageInfo messageInfoFor(Class<?> clazz) { 160 throw new IllegalStateException("This should never be called."); 161 } 162 }; 163 getDescriptorMessageInfoFactory()164 private static MessageInfoFactory getDescriptorMessageInfoFactory() { 165 try { 166 Class<?> clazz = Class.forName("com.google.protobuf.DescriptorMessageInfoFactory"); 167 return (MessageInfoFactory) clazz.getDeclaredMethod("getInstance").invoke(null); 168 } catch (Exception e) { 169 return EMPTY_FACTORY; 170 } 171 } 172 } 173