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 import java.util.ArrayList;
36 import java.util.Collections;
37 import java.util.List;
38 
39 /**
40  * Information for the layout of a protobuf message class. This describes all of the fields
41  * contained within a message.
42  */
43 @ExperimentalApi
44 final class StructuralMessageInfo implements MessageInfo {
45   private final ProtoSyntax syntax;
46   private final boolean messageSetWireFormat;
47   private final int[] checkInitialized;
48   private final FieldInfo[] fields;
49   private final MessageLite defaultInstance;
50 
51   /**
52    * Constructor.
53    *
54    * @param checkInitialized fields to check in isInitialized().
55    * @param fields the set of fields for the message, in field number order.
56    */
StructuralMessageInfo( ProtoSyntax syntax, boolean messageSetWireFormat, int[] checkInitialized, FieldInfo[] fields, Object defaultInstance)57   StructuralMessageInfo(
58       ProtoSyntax syntax,
59       boolean messageSetWireFormat,
60       int[] checkInitialized,
61       FieldInfo[] fields,
62       Object defaultInstance) {
63     this.syntax = syntax;
64     this.messageSetWireFormat = messageSetWireFormat;
65     this.checkInitialized = checkInitialized;
66     this.fields = fields;
67     this.defaultInstance = (MessageLite) checkNotNull(defaultInstance, "defaultInstance");
68   }
69 
70   /** Gets the syntax for the message (e.g. PROTO2, PROTO3). */
71   @Override
getSyntax()72   public ProtoSyntax getSyntax() {
73     return syntax;
74   }
75 
76   /** Indicates whether or not the message should be represented with message set wire format. */
77   @Override
isMessageSetWireFormat()78   public boolean isMessageSetWireFormat() {
79     return messageSetWireFormat;
80   }
81 
82   /** An array of field numbers that need to be checked for isInitialized(). */
getCheckInitialized()83   public int[] getCheckInitialized() {
84     return checkInitialized;
85   }
86 
87   /**
88    * Gets the information for all fields within this message, sorted in ascending order by their
89    * field number.
90    */
getFields()91   public FieldInfo[] getFields() {
92     return fields;
93   }
94 
95   @Override
getDefaultInstance()96   public MessageLite getDefaultInstance() {
97     return defaultInstance;
98   }
99 
100   /** Helper method for creating a new builder for {@link MessageInfo}. */
newBuilder()101   public static Builder newBuilder() {
102     return new Builder();
103   }
104 
105   /** Helper method for creating a new builder for {@link MessageInfo}. */
newBuilder(int numFields)106   public static Builder newBuilder(int numFields) {
107     return new Builder(numFields);
108   }
109 
110   /** A builder of {@link MessageInfo} instances. */
111   public static final class Builder {
112     private final List<FieldInfo> fields;
113     private ProtoSyntax syntax;
114     private boolean wasBuilt;
115     private boolean messageSetWireFormat;
116     private int[] checkInitialized = null;
117     private Object defaultInstance;
118 
Builder()119     public Builder() {
120       fields = new ArrayList<FieldInfo>();
121     }
122 
Builder(int numFields)123     public Builder(int numFields) {
124       fields = new ArrayList<FieldInfo>(numFields);
125     }
126 
withDefaultInstance(Object defaultInstance)127     public void withDefaultInstance(Object defaultInstance) {
128       this.defaultInstance = defaultInstance;
129     }
130 
withSyntax(ProtoSyntax syntax)131     public void withSyntax(ProtoSyntax syntax) {
132       this.syntax = checkNotNull(syntax, "syntax");
133     }
134 
withMessageSetWireFormat(boolean messageSetWireFormat)135     public void withMessageSetWireFormat(boolean messageSetWireFormat) {
136       this.messageSetWireFormat = messageSetWireFormat;
137     }
138 
withCheckInitialized(int[] checkInitialized)139     public void withCheckInitialized(int[] checkInitialized) {
140       this.checkInitialized = checkInitialized;
141     }
142 
withField(FieldInfo field)143     public void withField(FieldInfo field) {
144       if (wasBuilt) {
145         throw new IllegalStateException("Builder can only build once");
146       }
147       fields.add(field);
148     }
149 
build()150     public StructuralMessageInfo build() {
151       if (wasBuilt) {
152         throw new IllegalStateException("Builder can only build once");
153       }
154       if (syntax == null) {
155         throw new IllegalStateException("Must specify a proto syntax");
156       }
157       wasBuilt = true;
158       Collections.sort(fields);
159       return new StructuralMessageInfo(
160           syntax,
161           messageSetWireFormat,
162           checkInitialized,
163           fields.toArray(new FieldInfo[0]),
164           defaultInstance);
165     }
166   }
167 }
168