summaryrefslogtreecommitdiffstats
path: root/java
diff options
context:
space:
mode:
authorBrian Duff <bduff@google.com>2013-09-30 20:49:13 -0700
committerBrian Duff <bduff@google.com>2013-10-07 16:25:55 -0700
commit0b8579237336f221711a0aac42400eb31a58fed3 (patch)
treeac6553ae2998404642d43dfacd5d56a1a03412bf /java
parent9827c718c45cfa1744a3b0f8fc27dac9cd415603 (diff)
downloadexternal_protobuf-0b8579237336f221711a0aac42400eb31a58fed3.zip
external_protobuf-0b8579237336f221711a0aac42400eb31a58fed3.tar.gz
external_protobuf-0b8579237336f221711a0aac42400eb31a58fed3.tar.bz2
Add reftypes field generator option.
This option generates fields as reference types, and serializes based on nullness. Change-Id: Ic32e0eebff59d14016cc9a19e15a9bb08ae0bba5 Signed-off-by: Brian Duff <bduff@google.com>
Diffstat (limited to 'java')
-rw-r--r--java/README.txt71
-rw-r--r--java/pom.xml6
-rw-r--r--java/src/test/java/com/google/protobuf/NanoTest.java62
3 files changed, 120 insertions, 19 deletions
diff --git a/java/README.txt b/java/README.txt
index e2e698e..adc1972 100644
--- a/java/README.txt
+++ b/java/README.txt
@@ -487,34 +487,67 @@ java_nano_generate_has={true,false} (default: false)
many cases reading the default works and determining whether the
field was received over the wire is irrelevant.
-optional_field_style={default,accessors} (default: default)
- Defines the style of the generated code for _optional_ fields only.
+optional_field_style={default,accessors,reftypes} (default: default)
+ Defines the style of the generated code for fields.
+
+ * default *
+
In the default style, optional fields translate into public mutable
Java fields, and the serialization process is as discussed in the
- "IMPORTANT" section above. When set to 'accessors', each optional
- field is encapsulated behind 4 accessors, namely get<fieldname>(),
- set<fieldname>(), has<fieldname>() and clear<fieldname>() methods,
- with the standard semantics. The hazzer's return value determines
- whether a field is serialized, so this style is useful when you need
- to serialize a field with the default value, or check if a field has
- been explicitly set to its default value from the wire.
-
- Required fields are still translated to one public mutable Java
- field each, and repeated fields are still translated to arrays. No
- accessors are generated for them.
-
- optional_field_style=accessors cannot be used together with
- java_nano_generate_has=true. If you need the 'has' flag for any
- required field (you have no reason to), you can only use
- java_nano_generate_has=true.
+ "IMPORTANT" section above.
- IMPORTANT: When using the 'accessor' style, ProGuard should always
+ * accessors *
+
+ When set to 'accessors', each optional field is encapsulated behind
+ 4 accessors, namely get<fieldname>(), set<fieldname>(), has<fieldname>()
+ and clear<fieldname>() methods, with the standard semantics. The hazzer's
+ return value determines whether a field is serialized, so this style is
+ useful when you need to serialize a field with the default value, or check
+ if a field has been explicitly set to its default value from the wire.
+
+ In the 'accessors' style, required fields are still translated to one
+ public mutable Java field each, and repeated fields are still translated
+ to arrays. No accessors are generated for them.
+
+ IMPORTANT: When using the 'accessors' style, ProGuard should always
be enabled with optimization (don't use -dontoptimize) and allowing
access modification (use -allowaccessmodification). This removes the
unused accessors and maybe inline the rest at the call sites,
reducing the final code size.
TODO(maxtroy): find ProGuard config that would work the best.
+ * reftypes *
+
+ When set to 'reftypes', each proto field is generated as a public Java
+ field. For primitive types, these fields use the Java reference types
+ such as java.lang.Integer instead of primitive types such as int.
+
+ In the 'reftypes' style, fields are initialized to null (or empty
+ arrays for repeated fields), and their default values are not available.
+ They are serialized over the wire based on equality to null.
+
+ The 'reftypes' mode has some additional cost due to autoboxing and usage
+ of reference types. In practice, many boxed types are cached, and so don't
+ result in object creation. However, references do take slightly more memory
+ than primitives.
+
+ The 'reftypes' mode is useful when you want to be able to serialize fields
+ with default values, or check if a field has been explicitly set to the
+ default over the wire without paying the extra method cost of the
+ 'accessors' mode.
+
+ Note that if you attempt to write null to a required field in the reftypes
+ mode, serialization of the proto will cause a NullPointerException. This is
+ an intentional indicator that you must set required fields.
+
+
+ NOTE
+ optional_field_style=accessors or reftypes cannot be used together with
+ java_nano_generate_has=true. If you need the 'has' flag for any
+ required field (you have no reason to), you can only use
+ java_nano_generate_has=true.
+
+
To use nano protobufs:
- Link with the generated jar file
diff --git a/java/pom.xml b/java/pom.xml
index a34c164..1f43670 100644
--- a/java/pom.xml
+++ b/java/pom.xml
@@ -171,6 +171,12 @@
<arg value="../src/google/protobuf/unittest_enum_class_nano.proto" />
<arg value="../src/google/protobuf/unittest_enum_class_multiple_nano.proto" />
</exec>
+ <exec executable="../src/protoc">
+ <arg value="--javanano_out=optional_field_style=reftypes:target/generated-test-sources" />
+ <arg value="--proto_path=../src" />
+ <arg value="--proto_path=src/test/java" />
+ <arg value="../src/google/protobuf/unittest_reference_types_nano.proto" />
+ </exec>
</tasks>
<testSourceRoot>target/generated-test-sources</testSourceRoot>
<!--testSourceRoot>target/generated-test-sources/opt-space</testSourceRoot-->
diff --git a/java/src/test/java/com/google/protobuf/NanoTest.java b/java/src/test/java/com/google/protobuf/NanoTest.java
index ca0bcda..4f2ac3f 100644
--- a/java/src/test/java/com/google/protobuf/NanoTest.java
+++ b/java/src/test/java/com/google/protobuf/NanoTest.java
@@ -48,6 +48,7 @@ import com.google.protobuf.nano.NanoAccessorsOuterClass.TestNanoAccessors;
import com.google.protobuf.nano.NanoHasOuterClass.TestAllTypesNanoHas;
import com.google.protobuf.nano.NanoOuterClass;
import com.google.protobuf.nano.NanoOuterClass.TestAllTypesNano;
+import com.google.protobuf.nano.NanoReferenceTypes;
import com.google.protobuf.nano.UnittestImportNano;
import com.google.protobuf.nano.UnittestMultipleNano;
import com.google.protobuf.nano.UnittestRecursiveNano.RecursiveMessageNano;
@@ -2624,6 +2625,67 @@ public class NanoTest extends TestCase {
assertEquals(123, msg.synchronized_);
}
+ public void testReferenceTypesForPrimitives() throws Exception {
+ NanoReferenceTypes.TestAllTypesNano message = new NanoReferenceTypes.TestAllTypesNano();
+
+ // Base check - when nothing is set, we serialize nothing.
+ assertHasWireData(message, false);
+
+ message.defaultBool = true;
+ assertHasWireData(message, true);
+
+ message.defaultBool = false;
+ assertHasWireData(message, true);
+
+ message.defaultBool = null;
+ assertHasWireData(message, false);
+
+ message.defaultInt32 = 5;
+ assertHasWireData(message, true);
+
+ message.defaultInt32 = null;
+ assertHasWireData(message, false);
+
+ message.defaultInt64 = 123456L;
+ assertHasWireData(message, true);
+
+ message.defaultInt64 = null;
+ assertHasWireData(message, false);
+
+ message.defaultFloat = 1f;
+ assertHasWireData(message, true);
+
+ message.defaultFloat = null;
+ assertHasWireData(message, false);
+
+ message.defaultDouble = 2.1;
+ assertHasWireData(message, true);
+
+ message.defaultDouble = null;
+ assertHasWireData(message, false);
+
+ message.defaultString = "hello";
+ assertHasWireData(message, true);
+
+ message.defaultString = null;
+ assertHasWireData(message, false);
+
+ message.defaultBytes = new byte[] { 1, 2, 3 };
+ assertHasWireData(message, true);
+
+ message.defaultBytes = null;
+ assertHasWireData(message, false);
+ }
+
+ private void assertHasWireData(MessageNano message, boolean expected) {
+ int wireLength = MessageNano.toByteArray(message).length;
+ if (expected) {
+ assertFalse(wireLength == 0);
+ } else {
+ assertEquals(0, wireLength);
+ }
+ }
+
private <T> List<T> list(T first, T... remaining) {
List<T> list = new ArrayList<T>();
list.add(first);