diff options
Diffstat (limited to 'java/core/src/main/java')
6 files changed, 123 insertions, 35 deletions
diff --git a/java/core/src/main/java/com/google/protobuf/Android.java b/java/core/src/main/java/com/google/protobuf/Android.java new file mode 100644 index 00000000..cad54783 --- /dev/null +++ b/java/core/src/main/java/com/google/protobuf/Android.java @@ -0,0 +1,57 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +package com.google.protobuf; + +final class Android { + + private static final Class<?> MEMORY_CLASS = getClassForName("libcore.io.Memory"); + private static final boolean IS_ROBOLECTRIC = + getClassForName("org.robolectric.Robolectric") != null; + + /** Returns {@code true} if running on an Android device. */ + static boolean isOnAndroidDevice() { + return MEMORY_CLASS != null && !IS_ROBOLECTRIC; + } + + /** Returns the memory class or {@code null} if not on Android device. */ + static Class<?> getMemoryClass() { + return MEMORY_CLASS; + } + + @SuppressWarnings("unchecked") + private static <T> Class<T> getClassForName(String name) { + try { + return (Class<T>) Class.forName(name); + } catch (Throwable e) { + return null; + } + } +} diff --git a/java/core/src/main/java/com/google/protobuf/ByteString.java b/java/core/src/main/java/com/google/protobuf/ByteString.java index 99a31209..d67bb54a 100644 --- a/java/core/src/main/java/com/google/protobuf/ByteString.java +++ b/java/core/src/main/java/com/google/protobuf/ByteString.java @@ -124,14 +124,8 @@ public abstract class ByteString implements Iterable<Byte>, Serializable { private static final ByteArrayCopier byteArrayCopier; static { - boolean isAndroid = true; - try { - Class.forName("android.content.Context"); - } catch (ClassNotFoundException e) { - isAndroid = false; - } - - byteArrayCopier = isAndroid ? new SystemByteArrayCopier() : new ArraysByteArrayCopier(); + byteArrayCopier = + Android.isOnAndroidDevice() ? new SystemByteArrayCopier() : new ArraysByteArrayCopier(); } /** diff --git a/java/core/src/main/java/com/google/protobuf/FieldSet.java b/java/core/src/main/java/com/google/protobuf/FieldSet.java index 8a9239ed..c09daa32 100644 --- a/java/core/src/main/java/com/google/protobuf/FieldSet.java +++ b/java/core/src/main/java/com/google/protobuf/FieldSet.java @@ -102,6 +102,11 @@ final class FieldSet<FieldDescriptorType extends @SuppressWarnings("rawtypes") private static final FieldSet DEFAULT_INSTANCE = new FieldSet(true); + /** Returns {@code true} if empty, {@code false} otherwise. */ + boolean isEmpty() { + return fields.isEmpty(); + } + /** Make this FieldSet immutable from this point forward. */ @SuppressWarnings("unchecked") public void makeImmutable() { diff --git a/java/core/src/main/java/com/google/protobuf/GeneratedMessageLite.java b/java/core/src/main/java/com/google/protobuf/GeneratedMessageLite.java index 09084646..8b8d9fc6 100644 --- a/java/core/src/main/java/com/google/protobuf/GeneratedMessageLite.java +++ b/java/core/src/main/java/com/google/protobuf/GeneratedMessageLite.java @@ -504,11 +504,8 @@ public abstract class GeneratedMessageLite< extends GeneratedMessageLite<MessageType, BuilderType> implements ExtendableMessageOrBuilder<MessageType, BuilderType> { - /** - * Represents the set of extensions on this message. For use by generated - * code only. - */ - protected FieldSet<ExtensionDescriptor> extensions = FieldSet.newFieldSet(); + /** Represents the set of extensions on this message. For use by generated code only. */ + protected FieldSet<ExtensionDescriptor> extensions = FieldSet.emptySet(); @SuppressWarnings("unchecked") protected final void mergeExtensionFields(final MessageType other) { @@ -578,7 +575,11 @@ public abstract class GeneratedMessageLite< if (unknown) { // Unknown field or wrong wire type. Skip. return parseUnknownField(tag, input); } - + + if (extensions.isImmutable()) { + extensions = extensions.clone(); + } + if (packed) { int length = input.readRawVarint32(); int limit = input.pushLimit(length); @@ -942,12 +943,6 @@ public abstract class GeneratedMessageLite< implements ExtendableMessageOrBuilder<MessageType, BuilderType> { protected ExtendableBuilder(MessageType defaultInstance) { super(defaultInstance); - - // TODO(dweis): This is kind of an unnecessary clone since we construct a - // new instance in the parent constructor which makes the extensions - // immutable. This extra allocation shouldn't matter in practice - // though. - instance.extensions = instance.extensions.clone(); } // For immutable message conversion. @@ -966,6 +961,15 @@ public abstract class GeneratedMessageLite< instance.extensions = instance.extensions.clone(); } + private FieldSet<ExtensionDescriptor> ensureExtensionsAreMutable() { + FieldSet<ExtensionDescriptor> extensions = instance.extensions; + if (extensions.isImmutable()) { + extensions = extensions.clone(); + instance.extensions = extensions; + } + return extensions; + } + @Override public final MessageType buildPartial() { if (isBuilt) { @@ -1024,7 +1028,8 @@ public abstract class GeneratedMessageLite< verifyExtensionContainingType(extensionLite); copyOnWrite(); - instance.extensions.setField(extensionLite.descriptor, extensionLite.toFieldSetType(value)); + ensureExtensionsAreMutable() + .setField(extensionLite.descriptor, extensionLite.toFieldSetType(value)); return (BuilderType) this; } @@ -1037,8 +1042,9 @@ public abstract class GeneratedMessageLite< verifyExtensionContainingType(extensionLite); copyOnWrite(); - instance.extensions.setRepeatedField( - extensionLite.descriptor, index, extensionLite.singularToFieldSetType(value)); + ensureExtensionsAreMutable() + .setRepeatedField( + extensionLite.descriptor, index, extensionLite.singularToFieldSetType(value)); return (BuilderType) this; } @@ -1051,8 +1057,8 @@ public abstract class GeneratedMessageLite< verifyExtensionContainingType(extensionLite); copyOnWrite(); - instance.extensions.addRepeatedField( - extensionLite.descriptor, extensionLite.singularToFieldSetType(value)); + ensureExtensionsAreMutable() + .addRepeatedField(extensionLite.descriptor, extensionLite.singularToFieldSetType(value)); return (BuilderType) this; } @@ -1063,7 +1069,7 @@ public abstract class GeneratedMessageLite< verifyExtensionContainingType(extensionLite); copyOnWrite(); - instance.extensions.clearField(extensionLite.descriptor); + ensureExtensionsAreMutable().clearField(extensionLite.descriptor); return (BuilderType) this; } } diff --git a/java/core/src/main/java/com/google/protobuf/TextFormat.java b/java/core/src/main/java/com/google/protobuf/TextFormat.java index ab9acf2f..0c8b898c 100644 --- a/java/core/src/main/java/com/google/protobuf/TextFormat.java +++ b/java/core/src/main/java/com/google/protobuf/TextFormat.java @@ -1224,6 +1224,22 @@ public final class TextFormat { } /** + * Parse a text-format message from {@code input}. + * + * @return the parsed message, guaranteed initialized + */ + public static <T extends Message> T parse(final CharSequence input, + final Class<T> protoClass) + throws ParseException { + Message.Builder builder = + Internal.getDefaultInstance(protoClass).newBuilderForType(); + merge(input, builder); + @SuppressWarnings("unchecked") + T output = (T) builder.build(); + return output; + } + + /** * Parse a text-format message from {@code input} and merge the contents * into {@code builder}. Extensions will be recognized if they are * registered in {@code extensionRegistry}. @@ -1248,6 +1264,25 @@ public final class TextFormat { PARSER.merge(input, extensionRegistry, builder); } + /** + * Parse a text-format message from {@code input}. Extensions will be + * recognized if they are registered in {@code extensionRegistry}. + * + * @return the parsed message, guaranteed initialized + */ + public static <T extends Message> T parse( + final CharSequence input, + final ExtensionRegistry extensionRegistry, + final Class<T> protoClass) + throws ParseException { + Message.Builder builder = + Internal.getDefaultInstance(protoClass).newBuilderForType(); + merge(input, extensionRegistry, builder); + @SuppressWarnings("unchecked") + T output = (T) builder.build(); + return output; + } + /** * Parser for text-format proto2 instances. This class is thread-safe. diff --git a/java/core/src/main/java/com/google/protobuf/UnsafeUtil.java b/java/core/src/main/java/com/google/protobuf/UnsafeUtil.java index 88315cb6..98c93b90 100644 --- a/java/core/src/main/java/com/google/protobuf/UnsafeUtil.java +++ b/java/core/src/main/java/com/google/protobuf/UnsafeUtil.java @@ -364,15 +364,6 @@ final class UnsafeUtil { } - @SuppressWarnings("unchecked") - private static <T> Class<T> getClassForName(String name) { - try { - return (Class<T>) Class.forName(name); - } catch (Throwable e) { - return null; - } - } - /** Finds the address field within a direct {@link Buffer}. */ private static Field bufferAddressField() { return field(Buffer.class, "address"); |