• 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 java.util.Collections;
11 import java.util.HashMap;
12 import java.util.Map;
13 
14 /**
15  * Equivalent to {@link ExtensionRegistry} but supports only "lite" types.
16  *
17  * <p>If all of your types are lite types, then you only need to use {@code ExtensionRegistryLite}.
18  * Similarly, if all your types are regular types, then you only need {@link ExtensionRegistry}.
19  * Typically it does not make sense to mix the two, since if you have any regular types in your
20  * program, you then require the full runtime and lose all the benefits of the lite runtime, so you
21  * might as well make all your types be regular types. However, in some cases (e.g. when depending
22  * on multiple third-party libraries where one uses lite types and one uses regular), you may find
23  * yourself wanting to mix the two. In this case things get more complicated.
24  *
25  * <p>There are three factors to consider: Whether the type being extended is lite, whether the
26  * embedded type (in the case of a message-typed extension) is lite, and whether the extension
27  * itself is lite. Since all three are declared in different files, they could all be different.
28  * Here are all the combinations and which type of registry to use:
29  *
30  * <pre>
31  *   Extended type     Inner type    Extension         Use registry
32  *   =======================================================================
33  *   lite              lite          lite              ExtensionRegistryLite
34  *   lite              regular       lite              ExtensionRegistry
35  *   regular           regular       regular           ExtensionRegistry
36  *   all other combinations                            not supported
37  * </pre>
38  *
39  * <p>Note that just as regular types are not allowed to contain lite-type fields, they are also not
40  * allowed to contain lite-type extensions. This is because regular types must be fully accessible
41  * via reflection, which in turn means that all the inner messages must also support reflection. On
42  * the other hand, since regular types implement the entire lite interface, there is no problem with
43  * embedding regular types inside lite types.
44  *
45  * @author kenton@google.com Kenton Varda
46  */
47 public class ExtensionRegistryLite {
48 
49   // Set true to enable lazy parsing feature for MessageSet.
50   //
51   // TODO: Now we use a global flag to control whether enable lazy
52   // parsing feature for MessageSet, which may be too crude for some
53   // applications. Need to support this feature on smaller granularity.
54   private static volatile boolean eagerlyParseMessageSets = false;
55 
56   // Visible for testing.
57   static final String EXTENSION_CLASS_NAME = "com.google.protobuf.Extension";
58 
59   private static class ExtensionClassHolder {
60     static final Class<?> INSTANCE = resolveExtensionClass();
61 
resolveExtensionClass()62     static Class<?> resolveExtensionClass() {
63       try {
64         return Class.forName(EXTENSION_CLASS_NAME);
65       } catch (ClassNotFoundException e) {
66         // See comment in ExtensionRegistryFactory on the potential expense of this.
67         return null;
68       }
69     }
70   }
71 
isEagerlyParseMessageSets()72   public static boolean isEagerlyParseMessageSets() {
73     return eagerlyParseMessageSets;
74   }
75 
setEagerlyParseMessageSets(boolean isEagerlyParse)76   public static void setEagerlyParseMessageSets(boolean isEagerlyParse) {
77     eagerlyParseMessageSets = isEagerlyParse;
78   }
79 
80   /**
81    * Construct a new, empty instance.
82    *
83    * <p>This may be an {@code ExtensionRegistry} if the full (non-Lite) proto libraries are
84    * available.
85    */
newInstance()86   public static ExtensionRegistryLite newInstance() {
87     return Protobuf.assumeLiteRuntime
88         ? new ExtensionRegistryLite()
89         : ExtensionRegistryFactory.create();
90   }
91 
92   private static volatile ExtensionRegistryLite emptyRegistry;
93 
94   /**
95    * Get the unmodifiable singleton empty instance of either ExtensionRegistryLite or {@code
96    * ExtensionRegistry} (if the full (non-Lite) proto libraries are available).
97    */
getEmptyRegistry()98   public static ExtensionRegistryLite getEmptyRegistry() {
99     if (Protobuf.assumeLiteRuntime) {
100       return EMPTY_REGISTRY_LITE;
101     }
102     ExtensionRegistryLite result = emptyRegistry;
103     if (result == null) {
104       synchronized (ExtensionRegistryLite.class) {
105         result = emptyRegistry;
106         if (result == null) {
107           emptyRegistry = result = ExtensionRegistryFactory.createEmpty();
108         }
109       }
110     }
111     return result;
112   }
113 
114   /** Returns an unmodifiable view of the registry. */
getUnmodifiable()115   public ExtensionRegistryLite getUnmodifiable() {
116     return new ExtensionRegistryLite(this);
117   }
118 
119   /**
120    * Find an extension by containing type and field number.
121    *
122    * @return Information about the extension if found, or {@code null} otherwise.
123    */
124   @SuppressWarnings("unchecked")
125   public <ContainingType extends MessageLite>
findLiteExtensionByNumber( final ContainingType containingTypeDefaultInstance, final int fieldNumber)126       GeneratedMessageLite.GeneratedExtension<ContainingType, ?> findLiteExtensionByNumber(
127           final ContainingType containingTypeDefaultInstance, final int fieldNumber) {
128     return (GeneratedMessageLite.GeneratedExtension<ContainingType, ?>)
129         extensionsByNumber.get(new ObjectIntPair(containingTypeDefaultInstance, fieldNumber));
130   }
131 
132   /** Add an extension from a lite generated file to the registry. */
add(final GeneratedMessageLite.GeneratedExtension<?, ?> extension)133   public final void add(final GeneratedMessageLite.GeneratedExtension<?, ?> extension) {
134     extensionsByNumber.put(
135         new ObjectIntPair(extension.getContainingTypeDefaultInstance(), extension.getNumber()),
136         extension);
137   }
138 
139   /**
140    * Add an extension from a lite generated file to the registry only if it is a non-lite extension
141    * i.e. {@link GeneratedMessageLite.GeneratedExtension}.
142    */
add(ExtensionLite<?, ?> extension)143   public final void add(ExtensionLite<?, ?> extension) {
144     if (GeneratedMessageLite.GeneratedExtension.class.isAssignableFrom(extension.getClass())) {
145       add((GeneratedMessageLite.GeneratedExtension<?, ?>) extension);
146     }
147     if (!Protobuf.assumeLiteRuntime && ExtensionRegistryFactory.isFullRegistry(this)) {
148       try {
149         this.getClass().getMethod("add", ExtensionClassHolder.INSTANCE).invoke(this, extension);
150       } catch (Exception e) {
151         throw new IllegalArgumentException(
152             String.format("Could not invoke ExtensionRegistry#add for %s", extension), e);
153       }
154     }
155   }
156 
157   // =================================================================
158   // Private stuff.
159 
160   // Constructors are package-private so that ExtensionRegistry can subclass
161   // this.
162 
ExtensionRegistryLite()163   ExtensionRegistryLite() {
164     this.extensionsByNumber =
165         new HashMap<ObjectIntPair, GeneratedMessageLite.GeneratedExtension<?, ?>>();
166   }
167 
168   static final ExtensionRegistryLite EMPTY_REGISTRY_LITE = new ExtensionRegistryLite(true);
169 
ExtensionRegistryLite(ExtensionRegistryLite other)170   ExtensionRegistryLite(ExtensionRegistryLite other) {
171     if (other == EMPTY_REGISTRY_LITE) {
172       this.extensionsByNumber = Collections.emptyMap();
173     } else {
174       this.extensionsByNumber = Collections.unmodifiableMap(other.extensionsByNumber);
175     }
176   }
177 
178   private final Map<ObjectIntPair, GeneratedMessageLite.GeneratedExtension<?, ?>>
179       extensionsByNumber;
180 
ExtensionRegistryLite(boolean empty)181   ExtensionRegistryLite(boolean empty) {
182     this.extensionsByNumber = Collections.emptyMap();
183   }
184 
185   /** A (Object, int) pair, used as a map key. */
186   private static final class ObjectIntPair {
187     private final Object object;
188     private final int number;
189 
ObjectIntPair(final Object object, final int number)190     ObjectIntPair(final Object object, final int number) {
191       this.object = object;
192       this.number = number;
193     }
194 
195     @Override
hashCode()196     public int hashCode() {
197       return System.identityHashCode(object) * ((1 << 16) - 1) + number;
198     }
199 
200     @Override
equals(final Object obj)201     public boolean equals(final Object obj) {
202       if (!(obj instanceof ObjectIntPair)) {
203         return false;
204       }
205       final ObjectIntPair other = (ObjectIntPair) obj;
206       return object == other.object && number == other.number;
207     }
208   }
209 }
210