diff options
Diffstat (limited to 'java/src/main/java/com/google/protobuf/GeneratedMessage.java')
-rw-r--r-- | java/src/main/java/com/google/protobuf/GeneratedMessage.java | 212 |
1 files changed, 199 insertions, 13 deletions
diff --git a/java/src/main/java/com/google/protobuf/GeneratedMessage.java b/java/src/main/java/com/google/protobuf/GeneratedMessage.java index d8510cb5..9457d999 100644 --- a/java/src/main/java/com/google/protobuf/GeneratedMessage.java +++ b/java/src/main/java/com/google/protobuf/GeneratedMessage.java @@ -109,8 +109,15 @@ public abstract class GeneratedMessage extends AbstractMessage return internalGetFieldAccessorTable().descriptor; } - /** Internal helper which returns a mutable map. */ - private Map<FieldDescriptor, Object> getAllFieldsMutable() { + /** + * Internal helper to return a modifiable map containing all the fields. + * The returned Map is modifialbe so that the caller can add additional + * extension fields to implement {@link #getAllFields()}. + * + * @param getBytesForString whether to generate ByteString for string fields + */ + private Map<FieldDescriptor, Object> getAllFieldsMutable( + boolean getBytesForString) { final TreeMap<FieldDescriptor, Object> result = new TreeMap<FieldDescriptor, Object>(); final Descriptor descriptor = internalGetFieldAccessorTable().descriptor; @@ -122,7 +129,12 @@ public abstract class GeneratedMessage extends AbstractMessage } } else { if (hasField(field)) { - result.put(field, getField(field)); + if (getBytesForString + && field.getJavaType() == FieldDescriptor.JavaType.STRING) { + result.put(field, getFieldRaw(field)); + } else { + result.put(field, getField(field)); + } } } } @@ -161,7 +173,23 @@ public abstract class GeneratedMessage extends AbstractMessage //@Override (Java 1.6 override semantics, but we must support 1.5) public Map<FieldDescriptor, Object> getAllFields() { - return Collections.unmodifiableMap(getAllFieldsMutable()); + return Collections.unmodifiableMap( + getAllFieldsMutable(/* getBytesForString = */ false)); + } + + /** + * Returns a collection of all the fields in this message which are set + * and their corresponding values. A singular ("required" or "optional") + * field is set iff hasField() returns true for that field. A "repeated" + * field is set iff getRepeatedFieldCount() is greater than zero. The + * values are exactly what would be returned by calling + * {@link #getFieldRaw(Descriptors.FieldDescriptor)} for each field. The map + * is guaranteed to be a sorted map, so iterating over it will return fields + * in order by field number. + */ + Map<FieldDescriptor, Object> getAllFieldsRaw() { + return Collections.unmodifiableMap( + getAllFieldsMutable(/* getBytesForString = */ true)); } //@Override (Java 1.6 override semantics, but we must support 1.5) @@ -184,6 +212,18 @@ public abstract class GeneratedMessage extends AbstractMessage return internalGetFieldAccessorTable().getField(field).get(this); } + /** + * Obtains the value of the given field, or the default value if it is + * not set. For primitive fields, the boxed primitive value is returned. + * For enum fields, the EnumValueDescriptor for the value is returned. For + * embedded message fields, the sub-message is returned. For repeated + * fields, a java.util.List is returned. For present string fields, a + * ByteString is returned representing the bytes that the field contains. + */ + Object getFieldRaw(final FieldDescriptor field) { + return internalGetFieldAccessorTable().getField(field).getRaw(this); + } + //@Override (Java 1.6 override semantics, but we must support 1.5) public int getRepeatedFieldCount(final FieldDescriptor field) { return internalGetFieldAccessorTable().getField(field) @@ -214,6 +254,24 @@ public abstract class GeneratedMessage extends AbstractMessage return unknownFields.mergeFieldFrom(tag, input); } + @Override + public void writeTo(final CodedOutputStream output) throws IOException { + MessageReflection.writeMessageTo(this, getAllFieldsRaw(), output, false); + } + + @Override + public int getSerializedSize() { + int size = memoizedSize; + if (size != -1) { + return size; + } + + memoizedSize = MessageReflection.getSerializedSize( + this, getAllFieldsRaw()); + return memoizedSize; + } + + /** * Used by parsing constructors in generated classes. @@ -563,6 +621,15 @@ public abstract class GeneratedMessage extends AbstractMessage throw new RuntimeException( "No map fields found in " + getClass().getName()); } + + /** Like {@link internalGetMapField} but return a mutable version. */ + @SuppressWarnings({"unused", "rawtypes"}) + protected MapField internalGetMutableMapField(int fieldNumber) { + // Note that we can't use descriptor names here because this method will + // be called when descriptor is being initialized. + throw new RuntimeException( + "No map fields found in " + getClass().getName()); + } } // ================================================================= @@ -825,7 +892,16 @@ public abstract class GeneratedMessage extends AbstractMessage @Override public Map<FieldDescriptor, Object> getAllFields() { - final Map<FieldDescriptor, Object> result = super.getAllFieldsMutable(); + final Map<FieldDescriptor, Object> result = + super.getAllFieldsMutable(/* getBytesForString = */ false); + result.putAll(getExtensionFields()); + return Collections.unmodifiableMap(result); + } + + @Override + public Map<FieldDescriptor, Object> getAllFieldsRaw() { + final Map<FieldDescriptor, Object> result = + super.getAllFieldsMutable(/* getBytesForString = */ false); result.putAll(getExtensionFields()); return Collections.unmodifiableMap(result); } @@ -1761,6 +1837,10 @@ public abstract class GeneratedMessage extends AbstractMessage fields[i] = new SingularEnumFieldAccessor( field, camelCaseNames[i], messageClass, builderClass, containingOneofCamelCaseName); + } else if (field.getJavaType() == FieldDescriptor.JavaType.STRING) { + fields[i] = new SingularStringFieldAccessor( + field, camelCaseNames[i], messageClass, builderClass, + containingOneofCamelCaseName); } else { fields[i] = new SingularFieldAccessor( field, camelCaseNames[i], messageClass, builderClass, @@ -1817,9 +1897,13 @@ public abstract class GeneratedMessage extends AbstractMessage private interface FieldAccessor { Object get(GeneratedMessage message); Object get(GeneratedMessage.Builder builder); + Object getRaw(GeneratedMessage message); + Object getRaw(GeneratedMessage.Builder builder); void set(Builder builder, Object value); Object getRepeated(GeneratedMessage message, int index); Object getRepeated(GeneratedMessage.Builder builder, int index); + Object getRepeatedRaw(GeneratedMessage message, int index); + Object getRepeatedRaw(GeneratedMessage.Builder builder, int index); void setRepeated(Builder builder, int index, Object value); void addRepeated(Builder builder, Object value); @@ -1949,6 +2033,12 @@ public abstract class GeneratedMessage extends AbstractMessage public Object get(GeneratedMessage.Builder builder) { return invokeOrDie(getMethodBuilder, builder); } + public Object getRaw(final GeneratedMessage message) { + return get(message); + } + public Object getRaw(GeneratedMessage.Builder builder) { + return get(builder); + } public void set(final Builder builder, final Object value) { invokeOrDie(setMethod, builder, value); } @@ -1957,12 +2047,22 @@ public abstract class GeneratedMessage extends AbstractMessage throw new UnsupportedOperationException( "getRepeatedField() called on a singular field."); } + public Object getRepeatedRaw(final GeneratedMessage message, + final int index) { + throw new UnsupportedOperationException( + "getRepeatedFieldRaw() called on a singular field."); + } public Object getRepeated(GeneratedMessage.Builder builder, int index) { throw new UnsupportedOperationException( "getRepeatedField() called on a singular field."); } - public void setRepeated(final Builder builder, - final int index, final Object value) { + public Object getRepeatedRaw(GeneratedMessage.Builder builder, + int index) { + throw new UnsupportedOperationException( + "getRepeatedFieldRaw() called on a singular field."); + } + public void setRepeated(final Builder builder, final int index, + final Object value) { throw new UnsupportedOperationException( "setRepeatedField() called on a singular field."); } @@ -2058,6 +2158,12 @@ public abstract class GeneratedMessage extends AbstractMessage public Object get(GeneratedMessage.Builder builder) { return invokeOrDie(getMethodBuilder, builder); } + public Object getRaw(final GeneratedMessage message) { + return get(message); + } + public Object getRaw(GeneratedMessage.Builder builder) { + return get(builder); + } public void set(final Builder builder, final Object value) { // Add all the elements individually. This serves two purposes: // 1) Verifies that each element has the correct type. @@ -2075,6 +2181,13 @@ public abstract class GeneratedMessage extends AbstractMessage public Object getRepeated(GeneratedMessage.Builder builder, int index) { return invokeOrDie(getRepeatedMethodBuilder, builder, index); } + public Object getRepeatedRaw(GeneratedMessage message, int index) { + return getRepeated(message, index); + } + public Object getRepeatedRaw(GeneratedMessage.Builder builder, + int index) { + return getRepeated(builder, index); + } public void setRepeated(final Builder builder, final int index, final Object value) { invokeOrDie(setRepeatedMethod, builder, index, value); @@ -2139,6 +2252,12 @@ public abstract class GeneratedMessage extends AbstractMessage return (MapField<?, ?>) builder.internalGetMapField(field.getNumber()); } + private MapField<?, ?> getMutableMapField( + GeneratedMessage.Builder builder) { + return (MapField<?, ?>) builder.internalGetMutableMapField( + field.getNumber()); + } + public Object get(GeneratedMessage message) { List result = new ArrayList(); for (int i = 0; i < getRepeatedCount(message); i++) { @@ -2155,6 +2274,14 @@ public abstract class GeneratedMessage extends AbstractMessage return Collections.unmodifiableList(result); } + public Object getRaw(GeneratedMessage message) { + return get(message); + } + + public Object getRaw(GeneratedMessage.Builder builder) { + return get(builder); + } + public void set(Builder builder, Object value) { clear(builder); for (Object entry : (List) value) { @@ -2170,14 +2297,20 @@ public abstract class GeneratedMessage extends AbstractMessage return getMapField(builder).getList().get(index); } + public Object getRepeatedRaw(GeneratedMessage message, int index) { + return getRepeated(message, index); + } + + public Object getRepeatedRaw(Builder builder, int index) { + return getRepeated(builder, index); + } + public void setRepeated(Builder builder, int index, Object value) { - builder.onChanged(); - getMapField(builder).getMutableList().set(index, (Message) value); + getMutableMapField(builder).getMutableList().set(index, (Message) value); } public void addRepeated(Builder builder, Object value) { - builder.onChanged(); - getMapField(builder).getMutableList().add((Message) value); + getMutableMapField(builder).getMutableList().add((Message) value); } public boolean has(GeneratedMessage message) { @@ -2199,8 +2332,7 @@ public abstract class GeneratedMessage extends AbstractMessage } public void clear(Builder builder) { - builder.onChanged(); - getMapField(builder).getMutableList().clear(); + getMutableMapField(builder).getMutableList().clear(); } public com.google.protobuf.Message.Builder newBuilder() { @@ -2391,6 +2523,60 @@ public abstract class GeneratedMessage extends AbstractMessage // --------------------------------------------------------------- + /** + * Field accessor for string fields. + * + * <p>This class makes getFooBytes() and setFooBytes() available for + * reflection API so that reflection based serialize/parse functions can + * access the raw bytes of the field to preserve non-UTF8 bytes in the + * string. + * + * <p>This ensures the serialize/parse round-trip safety, which is important + * for servers which forward messages. + */ + private static final class SingularStringFieldAccessor + extends SingularFieldAccessor { + SingularStringFieldAccessor( + final FieldDescriptor descriptor, final String camelCaseName, + final Class<? extends GeneratedMessage> messageClass, + final Class<? extends Builder> builderClass, + final String containingOneofCamelCaseName) { + super(descriptor, camelCaseName, messageClass, builderClass, + containingOneofCamelCaseName); + getBytesMethod = getMethodOrDie(messageClass, + "get" + camelCaseName + "Bytes"); + getBytesMethodBuilder = getMethodOrDie(builderClass, + "get" + camelCaseName + "Bytes"); + setBytesMethodBuilder = getMethodOrDie(builderClass, + "set" + camelCaseName + "Bytes", ByteString.class); + } + + private final Method getBytesMethod; + private final Method getBytesMethodBuilder; + private final Method setBytesMethodBuilder; + + @Override + public Object getRaw(final GeneratedMessage message) { + return invokeOrDie(getBytesMethod, message); + } + + @Override + public Object getRaw(GeneratedMessage.Builder builder) { + return invokeOrDie(getBytesMethodBuilder, builder); + } + + @Override + public void set(GeneratedMessage.Builder builder, Object value) { + if (value instanceof ByteString) { + invokeOrDie(setBytesMethodBuilder, builder, value); + } else { + super.set(builder, value); + } + } + } + + // --------------------------------------------------------------- + private static final class SingularMessageFieldAccessor extends SingularFieldAccessor { SingularMessageFieldAccessor( |