Index: third_party/protobuf/java/src/main/java/com/google/protobuf/GeneratedMessage.java |
=================================================================== |
--- third_party/protobuf/java/src/main/java/com/google/protobuf/GeneratedMessage.java (revision 216642) |
+++ third_party/protobuf/java/src/main/java/com/google/protobuf/GeneratedMessage.java (working copy) |
@@ -58,8 +58,6 @@ |
implements Serializable { |
private static final long serialVersionUID = 1L; |
- private final UnknownFieldSet unknownFields; |
- |
/** |
* For testing. Allows a test to disable the optimization that avoids using |
* field builders for nested messages until they are requested. By disabling |
@@ -68,13 +66,16 @@ |
protected static boolean alwaysUseFieldBuilders = false; |
protected GeneratedMessage() { |
- this.unknownFields = UnknownFieldSet.getDefaultInstance(); |
} |
protected GeneratedMessage(Builder<?> builder) { |
- this.unknownFields = builder.getUnknownFields(); |
} |
+ public Parser<? extends Message> getParserForType() { |
+ throw new UnsupportedOperationException( |
+ "This is supposed to be overridden by subclasses."); |
+ } |
+ |
/** |
* For testing. Allows a test to disable the optimization that avoids using |
* field builders for nested messages until they are requested. By disabling |
@@ -175,10 +176,30 @@ |
} |
//@Override (Java 1.6 override semantics, but we must support 1.5) |
- public final UnknownFieldSet getUnknownFields() { |
- return unknownFields; |
+ public UnknownFieldSet getUnknownFields() { |
+ throw new UnsupportedOperationException( |
+ "This is supposed to be overridden by subclasses."); |
} |
+ /** |
+ * Called by subclasses to parse an unknown field. |
+ * @return {@code true} unless the tag is an end-group tag. |
+ */ |
+ protected boolean parseUnknownField( |
+ CodedInputStream input, |
+ UnknownFieldSet.Builder unknownFields, |
+ ExtensionRegistryLite extensionRegistry, |
+ int tag) throws IOException { |
+ return unknownFields.mergeFieldFrom(tag, input); |
+ } |
+ |
+ /** |
+ * Used by parsing constructors in generated classes. |
+ */ |
+ protected void makeExtensionsImmutable() { |
+ // Noop for messages without extensions. |
+ } |
+ |
protected abstract Message.Builder newBuilderForType(BuilderParent parent); |
/** |
@@ -319,6 +340,11 @@ |
} |
//@Override (Java 1.6 override semantics, but we must support 1.5) |
+ public Message.Builder getFieldBuilder(final FieldDescriptor field) { |
+ return internalGetFieldAccessorTable().getField(field).getBuilder(this); |
+ } |
+ |
+ //@Override (Java 1.6 override semantics, but we must support 1.5) |
public boolean hasField(final FieldDescriptor field) { |
return internalGetFieldAccessorTable().getField(field).has(this); |
} |
@@ -626,7 +652,26 @@ |
return super.isInitialized() && extensionsAreInitialized(); |
} |
+ @Override |
+ protected boolean parseUnknownField( |
+ CodedInputStream input, |
+ UnknownFieldSet.Builder unknownFields, |
+ ExtensionRegistryLite extensionRegistry, |
+ int tag) throws IOException { |
+ return AbstractMessage.Builder.mergeFieldFrom( |
+ input, unknownFields, extensionRegistry, getDescriptorForType(), |
+ null, extensions, tag); |
+ } |
+ |
/** |
+ * Used by parsing constructors in generated classes. |
+ */ |
+ @Override |
+ protected void makeExtensionsImmutable() { |
+ extensions.makeImmutable(); |
+ } |
+ |
+ /** |
* Used by subclasses to serialize extensions. Extension ranges may be |
* interleaved with field numbers, but we must write them in canonical |
* (sorted by field number) order. ExtensionWriter helps us write |
@@ -655,9 +700,21 @@ |
if (messageSetWireFormat && descriptor.getLiteJavaType() == |
WireFormat.JavaType.MESSAGE && |
!descriptor.isRepeated()) { |
- output.writeMessageSetExtension(descriptor.getNumber(), |
- (Message) next.getValue()); |
+ if (next instanceof LazyField.LazyEntry<?>) { |
+ output.writeRawMessageSetExtension(descriptor.getNumber(), |
+ ((LazyField.LazyEntry<?>) next).getField().toByteString()); |
+ } else { |
+ output.writeMessageSetExtension(descriptor.getNumber(), |
+ (Message) next.getValue()); |
+ } |
} else { |
+ // TODO(xiangl): Taken care of following code, it may cause |
+ // problem when we use LazyField for normal fields/extensions. |
+ // Due to the optional field can be duplicated at the end of |
+ // serialized bytes, which will make the serialized size change |
+ // after lazy field parsed. So when we use LazyField globally, |
+ // we need to change the following write method to write cached |
+ // bytes directly rather than write the parsed message. |
FieldSet.writeField(descriptor, next.getValue(), output); |
} |
if (iter.hasNext()) { |
@@ -974,7 +1031,8 @@ |
final ExtensionRegistryLite extensionRegistry, |
final int tag) throws IOException { |
return AbstractMessage.Builder.mergeFieldFrom( |
- input, unknownFields, extensionRegistry, this, tag); |
+ input, unknownFields, extensionRegistry, getDescriptorForType(), |
+ this, null, tag); |
} |
// --------------------------------------------------------------- |
@@ -1405,39 +1463,72 @@ |
final String[] camelCaseNames, |
final Class<? extends GeneratedMessage> messageClass, |
final Class<? extends Builder> builderClass) { |
+ this(descriptor, camelCaseNames); |
+ ensureFieldAccessorsInitialized(messageClass, builderClass); |
+ } |
+ |
+ /** |
+ * Construct a FieldAccessorTable for a particular message class without |
+ * initializing FieldAccessors. |
+ */ |
+ public FieldAccessorTable( |
+ final Descriptor descriptor, |
+ final String[] camelCaseNames) { |
this.descriptor = descriptor; |
+ this.camelCaseNames = camelCaseNames; |
fields = new FieldAccessor[descriptor.getFields().size()]; |
+ initialized = false; |
+ } |
- for (int i = 0; i < fields.length; i++) { |
- final FieldDescriptor field = descriptor.getFields().get(i); |
- if (field.isRepeated()) { |
- if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) { |
- fields[i] = new RepeatedMessageFieldAccessor( |
- field, camelCaseNames[i], messageClass, builderClass); |
- } else if (field.getJavaType() == FieldDescriptor.JavaType.ENUM) { |
- fields[i] = new RepeatedEnumFieldAccessor( |
- field, camelCaseNames[i], messageClass, builderClass); |
+ /** |
+ * Ensures the field accessors are initialized. This method is thread-safe. |
+ * |
+ * @param messageClass The message type. |
+ * @param builderClass The builder type. |
+ * @return this |
+ */ |
+ public FieldAccessorTable ensureFieldAccessorsInitialized( |
+ Class<? extends GeneratedMessage> messageClass, |
+ Class<? extends Builder> builderClass) { |
+ if (initialized) { return this; } |
+ synchronized (this) { |
+ if (initialized) { return this; } |
+ for (int i = 0; i < fields.length; i++) { |
+ FieldDescriptor field = descriptor.getFields().get(i); |
+ if (field.isRepeated()) { |
+ if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) { |
+ fields[i] = new RepeatedMessageFieldAccessor( |
+ field, camelCaseNames[i], messageClass, builderClass); |
+ } else if (field.getJavaType() == FieldDescriptor.JavaType.ENUM) { |
+ fields[i] = new RepeatedEnumFieldAccessor( |
+ field, camelCaseNames[i], messageClass, builderClass); |
+ } else { |
+ fields[i] = new RepeatedFieldAccessor( |
+ field, camelCaseNames[i], messageClass, builderClass); |
+ } |
} else { |
- fields[i] = new RepeatedFieldAccessor( |
- field, camelCaseNames[i], messageClass, builderClass); |
+ if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) { |
+ fields[i] = new SingularMessageFieldAccessor( |
+ field, camelCaseNames[i], messageClass, builderClass); |
+ } else if (field.getJavaType() == FieldDescriptor.JavaType.ENUM) { |
+ fields[i] = new SingularEnumFieldAccessor( |
+ field, camelCaseNames[i], messageClass, builderClass); |
+ } else { |
+ fields[i] = new SingularFieldAccessor( |
+ field, camelCaseNames[i], messageClass, builderClass); |
+ } |
} |
- } else { |
- if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) { |
- fields[i] = new SingularMessageFieldAccessor( |
- field, camelCaseNames[i], messageClass, builderClass); |
- } else if (field.getJavaType() == FieldDescriptor.JavaType.ENUM) { |
- fields[i] = new SingularEnumFieldAccessor( |
- field, camelCaseNames[i], messageClass, builderClass); |
- } else { |
- fields[i] = new SingularFieldAccessor( |
- field, camelCaseNames[i], messageClass, builderClass); |
- } |
} |
+ initialized = true; |
+ camelCaseNames = null; |
+ return this; |
} |
} |
private final Descriptor descriptor; |
private final FieldAccessor[] fields; |
+ private String[] camelCaseNames; |
+ private volatile boolean initialized; |
/** Get the FieldAccessor for a particular field. */ |
private FieldAccessor getField(final FieldDescriptor field) { |
@@ -1472,6 +1563,7 @@ |
int getRepeatedCount(GeneratedMessage.Builder builder); |
void clear(Builder builder); |
Message.Builder newBuilder(); |
+ Message.Builder getBuilder(GeneratedMessage.Builder builder); |
} |
// --------------------------------------------------------------- |
@@ -1551,6 +1643,10 @@ |
throw new UnsupportedOperationException( |
"newBuilderForField() called on a non-Message type."); |
} |
+ public Message.Builder getBuilder(GeneratedMessage.Builder builder) { |
+ throw new UnsupportedOperationException( |
+ "getFieldBuilder() called on a non-Message type."); |
+ } |
} |
private static class RepeatedFieldAccessor implements FieldAccessor { |
@@ -1573,8 +1669,6 @@ |
"get" + camelCaseName + "List"); |
getMethodBuilder = getMethodOrDie(builderClass, |
"get" + camelCaseName + "List"); |
- |
- |
getRepeatedMethod = |
getMethodOrDie(messageClass, "get" + camelCaseName, Integer.TYPE); |
getRepeatedMethodBuilder = |
@@ -1625,11 +1719,11 @@ |
} |
public boolean has(final GeneratedMessage message) { |
throw new UnsupportedOperationException( |
- "hasField() called on a singular field."); |
+ "hasField() called on a repeated field."); |
} |
public boolean has(GeneratedMessage.Builder builder) { |
throw new UnsupportedOperationException( |
- "hasField() called on a singular field."); |
+ "hasField() called on a repeated field."); |
} |
public int getRepeatedCount(final GeneratedMessage message) { |
return (Integer) invokeOrDie(getCountMethod, message); |
@@ -1644,6 +1738,10 @@ |
throw new UnsupportedOperationException( |
"newBuilderForField() called on a non-Message type."); |
} |
+ public Message.Builder getBuilder(GeneratedMessage.Builder builder) { |
+ throw new UnsupportedOperationException( |
+ "getFieldBuilder() called on a non-Message type."); |
+ } |
} |
// --------------------------------------------------------------- |
@@ -1753,9 +1851,12 @@ |
super(descriptor, camelCaseName, messageClass, builderClass); |
newBuilderMethod = getMethodOrDie(type, "newBuilder"); |
+ getBuilderMethodBuilder = |
+ getMethodOrDie(builderClass, "get" + camelCaseName + "Builder"); |
} |
private final Method newBuilderMethod; |
+ private final Method getBuilderMethodBuilder; |
private Object coerceType(final Object value) { |
if (type.isInstance(value)) { |
@@ -1766,7 +1867,7 @@ |
// DynamicMessage -- we should accept it. In this case we can make |
// a copy of the message. |
return ((Message.Builder) invokeOrDie(newBuilderMethod, null)) |
- .mergeFrom((Message) value).build(); |
+ .mergeFrom((Message) value).buildPartial(); |
} |
} |
@@ -1778,6 +1879,10 @@ |
public Message.Builder newBuilder() { |
return (Message.Builder) invokeOrDie(newBuilderMethod, null); |
} |
+ @Override |
+ public Message.Builder getBuilder(GeneratedMessage.Builder builder) { |
+ return (Message.Builder) invokeOrDie(getBuilderMethodBuilder, builder); |
+ } |
} |
private static final class RepeatedMessageFieldAccessor |
@@ -1825,7 +1930,7 @@ |
/** |
* Replaces this object in the output stream with a serialized form. |
* Part of Java's serialization magic. Generated sub-classes must override |
- * this method by calling <code>return super.writeReplace();</code> |
+ * this method by calling {@code return super.writeReplace();} |
* @return a SerializedForm of this message |
*/ |
protected Object writeReplace() throws ObjectStreamException { |