“A man got to have a code!” - Omar Little
Wire is a library for lightweight protocol buffers for mobile Java. Code generated by Wire has many fewer methods than standard protocol buffer code, which helps applications avoid the notorious 64k limit on methods in Android applications. Wire also generates clean, human-readable code for protocol buffer messages.
Wire is built using the Maven build system.
Build the wire-compiler using Maven (alternatively you can just download the wire-compiler .jar):
% mvn clean package
The wire-compiler
package contains the WireCompiler
class, which compiles standard .proto
files
into Java source code.
For example, to compile the file protos-repo/google/protobuf/descriptor.proto
, which may
(recursively) import other .proto
files within the protos-repo/
directory (replace
"VERSION" with the Wire version you are using):
% java -jar wire-compiler/target/wire-compiler-VERSION-jar-with-dependencies.jar \
--proto_path=protos-repo \
--java_out=out google/protobuf/descriptor.proto
Reading proto source file protos-repo/google/protobuf/descriptor.proto
Writing generated code to out/com/google/protobuf/DescriptorProtos.java
% head -11 out/com/google/protobuf/DescriptorProto.java
// Code generated by Wire protocol buffer compiler, do not edit.
// Source file: protos-repo/google/protobuf/descriptor.proto
package com.google.protobuf;
import com.squareup.wire.Message;
import com.squareup.wire.ProtoField;
import java.util.Collections;
import java.util.List;
public final class DescriptorProto
implements Message {
Instead of supplying individual filename arguments on the command line, the --files
flag may be
used to specify a single file containing a list of .proto
files. The file names are interpreted
relative to the value given for the --proto_path
flag.
% cat protos.include
google/protobuf/descriptor.proto
yourcompany/protos/stuff.proto
...
% java -jar wire-compiler/target/wire-compiler-1.0-SNAPSHOT-jar-with-dependencies.jar \
--proto_path=protos-repo \
--java_out=out \
--files=protos.include
Reading proto source file protos-repo/google/protobuf/descriptor.proto
Writing generated code to out/com/google/protobuf/DescriptorProtos.java
Reading proto source file protos-repo/yourcompany/protos/stuff.proto
Writing generated code to out/com/yourcompany/protos/stuff/Stuff.java
...
The compiler will (recursively) import any needed .proto
files from the protos-repo/
directory,
but will only generate output for the .proto
files listed on the command line or in the file
specified by the --files
flag.
To generate interface definitions for service
definitions in your .proto
files, use the
following compiler flag:
--service_writer=
fully_qualified_class_name
The named class must be on the classpath, must extend the com.squareup.wire.ServiceWriter
class,
and must have a public constructor taking a first argument of type JavaWriter
and a second
argument of type List<String>
which will contain user-specified options.
Three experimental sample implementations are currenly bundled with the compiler,
com.squareup.wire.SimpleServiceWriter
, com.squareup.wire.RetrofitServiceWriter
, and
com.squareup.wire.RxJavaServiceWriter
. If the --service_writer
flag is not present,
service
definitions are ignored.
A list of options may be passed to the ServiceWriter
using one or more instances of the
following compiler flag:
--service_writer_opt=
option
The options from each instance of the flag will be placed into a List
and passed as the
second parameter of the ServiceWriter
's constructor.
Given the following service definition:
service ExampleService {
/* Sends some data. */
rpc SendSomeData (SendDataRequest) returns (SendDataResponse);
}
com.squareup.wire.SimpleServiceWriter
will generate:
public interface ExampleService {
/**
* Sends some data.
*/
SendDataResponse sendSomeData(SendDataRequest sendDataRequest)
throws IOException;
}
com.squareup.wire.RetrofitServiceWriter
will generate:
public interface ExampleService {
/**
* Sends some data.
*/
@POST("/com.squareup.services.ExampleService/SendSomeData")
SendDataResponse sendSomeData(@Body SendDataRequest request);
}
and com.squareup.wire.RxJavaServiceWriter
will generate:
public final class RxJavaService {
public interface Endpoint {
/**
* Sends some data.
*/
@POST("/com.squareup.services.RxJavaService/SendSomeData")
SendDataResponse sendSomeData(@Body SendDataRequest request);
}
private final Func1<SendDataRequest, SendDataResponse> sendSomeData =
new Func1<SendDataRequest, SendDataResponse>() {
@Override
public SendDataResponse call(SendDataRequest request) {
return endpoint.sendSomeData(request);
}
};
private final Endpoint endpoint;
@Inject
public RxJavaService(Endpoint endpoint) {
this.endpoint = endpoint;
}
public Func1<SendDataRequest, SendDataResponse> getSendSomeData() {
return sendSomeData;
}
}
(omitting the generated file comment, package declaration, and imports for clarity).
If you would like to only generate interface definitions for some of the methods on a Service
,
use the --roots
flag and specify each one as fully.qualified.Service#MethodName
.
The wire-runtime
package contains runtime support libraries that must be included in applications
that use Wire-generated code.
Download the latest runtime .jar or depend via Maven:
<dependency>
<groupId>com.squareup.wire</groupId>
<artifactId>wire-runtime</artifactId>
<version>VERSION</version>
</dependency>
or Gradle:
compile 'com.squareup.wire:wire-runtime:VERSION'
where VERSION
is replaced by an actual version number such as 1.5.0
.
The Wire compiler generates a Java class for each message or enum defined in a .proto file
specified on the command line. Each message class has an associated Builder class that may be used
to construct an instance manually:
MyMessage msg = new MyMessage.Builder().some_int_field(123).build();
Note that field names are not converted to camel case.
Wire messages contain a public final
field for each field of the protocol buffer message.
Each field is annotated with a @ProtoField
annotation containing the field metadata required
by the Wire runtime.
Numeric and boolean values are stored using boxed primitive types (e.g., Integer or Long).
If a field is unset, its value is null
. Wire does not generate methods such as getXXX()
,
hasXXX()
, setXXX(
), etc. Repeated fields are stored as Lists of values.
A field some_field
has a constant DEFAULT_SOME_FIELD
containing the default value for that
field. A convenience method Wire.get
allows substitution of a default value for null
:
// Equivalent to:
// x = msg.some_field != null ? msg.some_field : MyMessage.DEFAULT_SOME_FIELD
int x = Wire.get(msg.some_field, MyMessage.DEFAULT_SOME_FIELD);
Builders contain a public
field for each field of the protocol buffer message, as well as
a method with the same name that sets the given value and returns the Builder instance for
chaining.
You can serialize a message by calling its write
or toByteArray
methods:
byte[] serializedMsg = msg.toByteArray();
To parse messages from their serialized representations, use the Wire
class. Typically you
will want to create a singleton instance of Wire
for use throughout your application.
Wire wire = new Wire();
MyMessage newMsg = wire.parseFrom(serializedMsg, MyMessage.class);
int x = newMsg.some_int_field; // 123
To use protocol buffer extensions, pass the classes that define the extensions you
wish to use as arguments to the Wire
constructor:
// Assume MessageWithExtensions contains a message SomeMessage that defines
// an extension field some_extension to the MyMessage message.
Wire wire = new Wire(Ext_SomeMessage.class);
MyMessage msg = new MyMessage.Builder()
.setExtension(Ext_SomeMessage.some_extension, 3)
.build();
int x = msg.getExtension(Ext_SomeMessage.some_extension); // 3
Wire does not support:
- Groups - they are skipped when parsing binary input data
Wire supports custom options on messages and fields. Other custom options are ignored. Use the
--no_options
flag to omit option information from the generated code.