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 com.google.protobuf.Descriptors.EnumValueDescriptor;
34 import com.google.protobuf.Descriptors.FieldDescriptor;
35 import com.google.protobuf.Descriptors.OneofDescriptor;
36 import com.google.protobuf.Internal.EnumLite;
37 
38 import java.io.IOException;
39 import java.io.InputStream;
40 import java.util.Arrays;
41 import java.util.Collections;
42 import java.util.HashMap;
43 import java.util.Iterator;
44 import java.util.List;
45 import java.util.Map;
46 
47 /**
48  * A partial implementation of the {@link Message} interface which implements
49  * as many methods of that interface as possible in terms of other methods.
50  *
51  * @author kenton@google.com Kenton Varda
52  */
53 public abstract class AbstractMessage
54     // TODO(dweis): Update GeneratedMessage to parameterize with MessageType and BuilderType.
55     extends AbstractMessageLite
56     implements Message {
57 
58   @Override
isInitialized()59   public boolean isInitialized() {
60     return MessageReflection.isInitialized(this);
61   }
62 
63 
64   @Override
findInitializationErrors()65   public List<String> findInitializationErrors() {
66     return MessageReflection.findMissingFields(this);
67   }
68 
69   @Override
getInitializationErrorString()70   public String getInitializationErrorString() {
71     return MessageReflection.delimitWithCommas(findInitializationErrors());
72   }
73 
74   /** TODO(jieluo): Clear it when all subclasses have implemented this method. */
75   @Override
hasOneof(OneofDescriptor oneof)76   public boolean hasOneof(OneofDescriptor oneof) {
77     throw new UnsupportedOperationException("hasOneof() is not implemented.");
78   }
79 
80   /** TODO(jieluo): Clear it when all subclasses have implemented this method. */
81   @Override
getOneofFieldDescriptor(OneofDescriptor oneof)82   public FieldDescriptor getOneofFieldDescriptor(OneofDescriptor oneof) {
83     throw new UnsupportedOperationException(
84         "getOneofFieldDescriptor() is not implemented.");
85   }
86 
87   @Override
toString()88   public final String toString() {
89     return TextFormat.printToString(this);
90   }
91 
92   @Override
writeTo(final CodedOutputStream output)93   public void writeTo(final CodedOutputStream output) throws IOException {
94     MessageReflection.writeMessageTo(this, getAllFields(), output, false);
95   }
96 
97   protected int memoizedSize = -1;
98 
99   @Override
getSerializedSize()100   public int getSerializedSize() {
101     int size = memoizedSize;
102     if (size != -1) {
103       return size;
104     }
105 
106     memoizedSize = MessageReflection.getSerializedSize(this, getAllFields());
107     return memoizedSize;
108   }
109 
110   @Override
equals(final Object other)111   public boolean equals(final Object other) {
112     if (other == this) {
113       return true;
114     }
115     if (!(other instanceof Message)) {
116       return false;
117     }
118     final Message otherMessage = (Message) other;
119     if (getDescriptorForType() != otherMessage.getDescriptorForType()) {
120       return false;
121     }
122     return compareFields(getAllFields(), otherMessage.getAllFields()) &&
123         getUnknownFields().equals(otherMessage.getUnknownFields());
124   }
125 
126   @Override
hashCode()127   public int hashCode() {
128     int hash = memoizedHashCode;
129     if (hash == 0) {
130       hash = 41;
131       hash = (19 * hash) + getDescriptorForType().hashCode();
132       hash = hashFields(hash, getAllFields());
133       hash = (29 * hash) + getUnknownFields().hashCode();
134       memoizedHashCode = hash;
135     }
136     return hash;
137   }
138 
toByteString(Object value)139   private static ByteString toByteString(Object value) {
140     if (value instanceof byte[]) {
141       return ByteString.copyFrom((byte[]) value);
142     } else {
143       return (ByteString) value;
144     }
145   }
146 
147   /**
148    * Compares two bytes fields. The parameters must be either a byte array or a
149    * ByteString object. They can be of different type though.
150    */
compareBytes(Object a, Object b)151   private static boolean compareBytes(Object a, Object b) {
152     if (a instanceof byte[] && b instanceof byte[]) {
153       return Arrays.equals((byte[])a, (byte[])b);
154     }
155     return toByteString(a).equals(toByteString(b));
156   }
157 
158   /**
159    * Converts a list of MapEntry messages into a Map used for equals() and
160    * hashCode().
161    */
162   @SuppressWarnings({"rawtypes", "unchecked"})
convertMapEntryListToMap(List list)163   private static Map convertMapEntryListToMap(List list) {
164     if (list.isEmpty()) {
165       return Collections.emptyMap();
166     }
167     Map result = new HashMap();
168     Iterator iterator = list.iterator();
169     Message entry = (Message) iterator.next();
170     Descriptors.Descriptor descriptor = entry.getDescriptorForType();
171     Descriptors.FieldDescriptor key = descriptor.findFieldByName("key");
172     Descriptors.FieldDescriptor value = descriptor.findFieldByName("value");
173     Object fieldValue = entry.getField(value);
174     if (fieldValue instanceof EnumValueDescriptor) {
175       fieldValue = ((EnumValueDescriptor) fieldValue).getNumber();
176     }
177     result.put(entry.getField(key), fieldValue);
178     while (iterator.hasNext()) {
179       entry = (Message) iterator.next();
180       fieldValue = entry.getField(value);
181       if (fieldValue instanceof EnumValueDescriptor) {
182         fieldValue = ((EnumValueDescriptor) fieldValue).getNumber();
183       }
184       result.put(entry.getField(key), fieldValue);
185     }
186     return result;
187   }
188 
189   /**
190    * Compares two map fields. The parameters must be a list of MapEntry
191    * messages.
192    */
193   @SuppressWarnings({"rawtypes", "unchecked"})
compareMapField(Object a, Object b)194   private static boolean compareMapField(Object a, Object b) {
195     Map ma = convertMapEntryListToMap((List) a);
196     Map mb = convertMapEntryListToMap((List) b);
197     return MapFieldLite.equals(ma, mb);
198   }
199 
200   /**
201    * Compares two set of fields.
202    * This method is used to implement {@link AbstractMessage#equals(Object)}
203    * and {@link AbstractMutableMessage#equals(Object)}. It takes special care
204    * of bytes fields because immutable messages and mutable messages use
205    * different Java type to reprensent a bytes field and this method should be
206    * able to compare immutable messages, mutable messages and also an immutable
207    * message to a mutable message.
208    */
compareFields(Map<FieldDescriptor, Object> a, Map<FieldDescriptor, Object> b)209   static boolean compareFields(Map<FieldDescriptor, Object> a,
210       Map<FieldDescriptor, Object> b) {
211     if (a.size() != b.size()) {
212       return false;
213     }
214     for (FieldDescriptor descriptor : a.keySet()) {
215       if (!b.containsKey(descriptor)) {
216         return false;
217       }
218       Object value1 = a.get(descriptor);
219       Object value2 = b.get(descriptor);
220       if (descriptor.getType() == FieldDescriptor.Type.BYTES) {
221         if (descriptor.isRepeated()) {
222           List list1 = (List) value1;
223           List list2 = (List) value2;
224           if (list1.size() != list2.size()) {
225             return false;
226           }
227           for (int i = 0; i < list1.size(); i++) {
228             if (!compareBytes(list1.get(i), list2.get(i))) {
229               return false;
230             }
231           }
232         } else {
233           // Compares a singular bytes field.
234           if (!compareBytes(value1, value2)) {
235             return false;
236           }
237         }
238       } else if (descriptor.isMapField()) {
239         if (!compareMapField(value1, value2)) {
240           return false;
241         }
242       } else {
243         // Compare non-bytes fields.
244         if (!value1.equals(value2)) {
245           return false;
246         }
247       }
248     }
249     return true;
250   }
251 
252   /**
253    * Calculates the hash code of a map field. {@code value} must be a list of
254    * MapEntry messages.
255    */
256   @SuppressWarnings("unchecked")
hashMapField(Object value)257   private static int hashMapField(Object value) {
258     return MapFieldLite.calculateHashCodeForMap(convertMapEntryListToMap((List) value));
259   }
260 
261   /** Get a hash code for given fields and values, using the given seed. */
262   @SuppressWarnings("unchecked")
hashFields(int hash, Map<FieldDescriptor, Object> map)263   protected static int hashFields(int hash, Map<FieldDescriptor, Object> map) {
264     for (Map.Entry<FieldDescriptor, Object> entry : map.entrySet()) {
265       FieldDescriptor field = entry.getKey();
266       Object value = entry.getValue();
267       hash = (37 * hash) + field.getNumber();
268       if (field.isMapField()) {
269         hash = (53 * hash) + hashMapField(value);
270       } else if (field.getType() != FieldDescriptor.Type.ENUM){
271         hash = (53 * hash) + value.hashCode();
272       } else if (field.isRepeated()) {
273         List<? extends EnumLite> list = (List<? extends EnumLite>) value;
274         hash = (53 * hash) + Internal.hashEnumList(list);
275       } else {
276         hash = (53 * hash) + Internal.hashEnum((EnumLite) value);
277       }
278     }
279     return hash;
280   }
281 
282   /**
283    * Package private helper method for AbstractParser to create
284    * UninitializedMessageException with missing field information.
285    */
286   @Override
newUninitializedMessageException()287   UninitializedMessageException newUninitializedMessageException() {
288     return Builder.newUninitializedMessageException(this);
289   }
290 
291   // =================================================================
292 
293   /**
294    * A partial implementation of the {@link Message.Builder} interface which
295    * implements as many methods of that interface as possible in terms of
296    * other methods.
297    */
298   @SuppressWarnings("unchecked")
299   public static abstract class Builder<BuilderType extends Builder<BuilderType>>
300       extends AbstractMessageLite.Builder
301       implements Message.Builder {
302     // The compiler produces an error if this is not declared explicitly.
303     @Override
clone()304     public abstract BuilderType clone();
305 
306     /** TODO(jieluo): Clear it when all subclasses have implemented this method. */
307     @Override
hasOneof(OneofDescriptor oneof)308     public boolean hasOneof(OneofDescriptor oneof) {
309       throw new UnsupportedOperationException("hasOneof() is not implemented.");
310     }
311 
312     /** TODO(jieluo): Clear it when all subclasses have implemented this method. */
313     @Override
getOneofFieldDescriptor(OneofDescriptor oneof)314     public FieldDescriptor getOneofFieldDescriptor(OneofDescriptor oneof) {
315       throw new UnsupportedOperationException(
316           "getOneofFieldDescriptor() is not implemented.");
317     }
318 
319     /** TODO(jieluo): Clear it when all subclasses have implemented this method. */
320     @Override
clearOneof(OneofDescriptor oneof)321     public BuilderType clearOneof(OneofDescriptor oneof) {
322       throw new UnsupportedOperationException("clearOneof() is not implemented.");
323     }
324 
325     @Override
clear()326     public BuilderType clear() {
327       for (final Map.Entry<FieldDescriptor, Object> entry :
328            getAllFields().entrySet()) {
329         clearField(entry.getKey());
330       }
331       return (BuilderType) this;
332     }
333 
334     @Override
findInitializationErrors()335     public List<String> findInitializationErrors() {
336       return MessageReflection.findMissingFields(this);
337     }
338 
339     @Override
getInitializationErrorString()340     public String getInitializationErrorString() {
341       return MessageReflection.delimitWithCommas(findInitializationErrors());
342     }
343 
344     @Override
internalMergeFrom(AbstractMessageLite other)345     protected BuilderType internalMergeFrom(AbstractMessageLite other) {
346       return mergeFrom((Message) other);
347     }
348 
349     @Override
mergeFrom(final Message other)350     public BuilderType mergeFrom(final Message other) {
351       if (other.getDescriptorForType() != getDescriptorForType()) {
352         throw new IllegalArgumentException(
353           "mergeFrom(Message) can only merge messages of the same type.");
354       }
355 
356       // Note:  We don't attempt to verify that other's fields have valid
357       //   types.  Doing so would be a losing battle.  We'd have to verify
358       //   all sub-messages as well, and we'd have to make copies of all of
359       //   them to insure that they don't change after verification (since
360       //   the Message interface itself cannot enforce immutability of
361       //   implementations).
362       // TODO(kenton):  Provide a function somewhere called makeDeepCopy()
363       //   which allows people to make secure deep copies of messages.
364 
365       for (final Map.Entry<FieldDescriptor, Object> entry :
366            other.getAllFields().entrySet()) {
367         final FieldDescriptor field = entry.getKey();
368         if (field.isRepeated()) {
369           for (final Object element : (List)entry.getValue()) {
370             addRepeatedField(field, element);
371           }
372         } else if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
373           final Message existingValue = (Message)getField(field);
374           if (existingValue == existingValue.getDefaultInstanceForType()) {
375             setField(field, entry.getValue());
376           } else {
377             setField(field,
378               existingValue.newBuilderForType()
379                 .mergeFrom(existingValue)
380                 .mergeFrom((Message)entry.getValue())
381                 .build());
382           }
383         } else {
384           setField(field, entry.getValue());
385         }
386       }
387 
388       mergeUnknownFields(other.getUnknownFields());
389 
390       return (BuilderType) this;
391     }
392 
393     @Override
mergeFrom(final CodedInputStream input)394     public BuilderType mergeFrom(final CodedInputStream input)
395                                  throws IOException {
396       return mergeFrom(input, ExtensionRegistry.getEmptyRegistry());
397     }
398 
399     @Override
mergeFrom( final CodedInputStream input, final ExtensionRegistryLite extensionRegistry)400     public BuilderType mergeFrom(
401         final CodedInputStream input,
402         final ExtensionRegistryLite extensionRegistry)
403         throws IOException {
404       final UnknownFieldSet.Builder unknownFields =
405         UnknownFieldSet.newBuilder(getUnknownFields());
406       while (true) {
407         final int tag = input.readTag();
408         if (tag == 0) {
409           break;
410         }
411 
412         MessageReflection.BuilderAdapter builderAdapter =
413             new MessageReflection.BuilderAdapter(this);
414         if (!MessageReflection.mergeFieldFrom(input, unknownFields,
415                                               extensionRegistry,
416                                               getDescriptorForType(),
417                                               builderAdapter,
418                                               tag)) {
419           // end group tag
420           break;
421         }
422       }
423       setUnknownFields(unknownFields.build());
424       return (BuilderType) this;
425     }
426 
427     @Override
mergeUnknownFields(final UnknownFieldSet unknownFields)428     public BuilderType mergeUnknownFields(final UnknownFieldSet unknownFields) {
429       setUnknownFields(
430         UnknownFieldSet.newBuilder(getUnknownFields())
431                        .mergeFrom(unknownFields)
432                        .build());
433       return (BuilderType) this;
434     }
435 
436     @Override
getFieldBuilder(final FieldDescriptor field)437     public Message.Builder getFieldBuilder(final FieldDescriptor field) {
438       throw new UnsupportedOperationException(
439           "getFieldBuilder() called on an unsupported message type.");
440     }
441 
442     @Override
getRepeatedFieldBuilder(final FieldDescriptor field, int index)443     public Message.Builder getRepeatedFieldBuilder(final FieldDescriptor field, int index) {
444       throw new UnsupportedOperationException(
445           "getRepeatedFieldBuilder() called on an unsupported message type.");
446     }
447 
448     @Override
toString()449     public String toString() {
450       return TextFormat.printToString(this);
451     }
452 
453     /**
454      * Construct an UninitializedMessageException reporting missing fields in
455      * the given message.
456      */
457     protected static UninitializedMessageException
newUninitializedMessageException(Message message)458         newUninitializedMessageException(Message message) {
459       return new UninitializedMessageException(
460           MessageReflection.findMissingFields(message));
461     }
462 
463     // ===============================================================
464     // The following definitions seem to be required in order to make javac
465     // not produce weird errors like:
466     //
467     // java/com/google/protobuf/DynamicMessage.java:203: types
468     //   com.google.protobuf.AbstractMessage.Builder<
469     //     com.google.protobuf.DynamicMessage.Builder> and
470     //   com.google.protobuf.AbstractMessage.Builder<
471     //     com.google.protobuf.DynamicMessage.Builder> are incompatible; both
472     //   define mergeFrom(com.google.protobuf.ByteString), but with unrelated
473     //   return types.
474     //
475     // Strangely, these lines are only needed if javac is invoked separately
476     // on AbstractMessage.java and AbstractMessageLite.java.  If javac is
477     // invoked on both simultaneously, it works.  (Or maybe the important
478     // point is whether or not DynamicMessage.java is compiled together with
479     // AbstractMessageLite.java -- not sure.)  I suspect this is a compiler
480     // bug.
481 
482     @Override
mergeFrom(final ByteString data)483     public BuilderType mergeFrom(final ByteString data)
484         throws InvalidProtocolBufferException {
485       return (BuilderType) super.mergeFrom(data);
486     }
487 
488     @Override
mergeFrom( final ByteString data, final ExtensionRegistryLite extensionRegistry)489     public BuilderType mergeFrom(
490         final ByteString data,
491         final ExtensionRegistryLite extensionRegistry)
492         throws InvalidProtocolBufferException {
493       return (BuilderType) super.mergeFrom(data, extensionRegistry);
494     }
495 
496     @Override
mergeFrom(final byte[] data)497     public BuilderType mergeFrom(final byte[] data)
498         throws InvalidProtocolBufferException {
499       return (BuilderType) super.mergeFrom(data);
500     }
501 
502     @Override
mergeFrom( final byte[] data, final int off, final int len)503     public BuilderType mergeFrom(
504         final byte[] data, final int off, final int len)
505         throws InvalidProtocolBufferException {
506       return (BuilderType) super.mergeFrom(data, off, len);
507     }
508 
509     @Override
mergeFrom( final byte[] data, final ExtensionRegistryLite extensionRegistry)510     public BuilderType mergeFrom(
511         final byte[] data,
512         final ExtensionRegistryLite extensionRegistry)
513         throws InvalidProtocolBufferException {
514       return (BuilderType) super.mergeFrom(data, extensionRegistry);
515     }
516 
517     @Override
mergeFrom( final byte[] data, final int off, final int len, final ExtensionRegistryLite extensionRegistry)518     public BuilderType mergeFrom(
519         final byte[] data, final int off, final int len,
520         final ExtensionRegistryLite extensionRegistry)
521         throws InvalidProtocolBufferException {
522       return (BuilderType) super.mergeFrom(data, off, len, extensionRegistry);
523     }
524 
525     @Override
mergeFrom(final InputStream input)526     public BuilderType mergeFrom(final InputStream input)
527         throws IOException {
528       return (BuilderType) super.mergeFrom(input);
529     }
530 
531     @Override
mergeFrom( final InputStream input, final ExtensionRegistryLite extensionRegistry)532     public BuilderType mergeFrom(
533         final InputStream input,
534         final ExtensionRegistryLite extensionRegistry)
535         throws IOException {
536       return (BuilderType) super.mergeFrom(input, extensionRegistry);
537     }
538 
539     @Override
mergeDelimitedFrom(final InputStream input)540     public boolean mergeDelimitedFrom(final InputStream input)
541         throws IOException {
542       return super.mergeDelimitedFrom(input);
543     }
544 
545     @Override
mergeDelimitedFrom( final InputStream input, final ExtensionRegistryLite extensionRegistry)546     public boolean mergeDelimitedFrom(
547         final InputStream input,
548         final ExtensionRegistryLite extensionRegistry)
549         throws IOException {
550       return super.mergeDelimitedFrom(input, extensionRegistry);
551     }
552   }
553 }
554