Skip to content

Commit

Permalink
Merge pull request square#311 from square/jw/omar-comin-yo
Browse files Browse the repository at this point in the history
Add a first-party converter for Wire.
  • Loading branch information
JakeWharton committed Aug 24, 2013
2 parents 23f1935 + d9c8796 commit c2e65d2
Show file tree
Hide file tree
Showing 6 changed files with 421 additions and 1 deletion.
7 changes: 6 additions & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@
<!-- Converter Dependencies -->
<protobuf.version>2.5.0</protobuf.version>
<jackson.version>2.2.2</jackson.version>
<wire.version>1.0.0</wire.version>

<!-- Test Dependencies -->
<junit.version>4.10</junit.version>
Expand Down Expand Up @@ -113,7 +114,11 @@
<artifactId>jackson-databind</artifactId>
<version>${jackson.version}</version>
</dependency>

<dependency>
<groupId>com.squareup.wire</groupId>
<artifactId>wire-runtime</artifactId>
<version>${wire.version}</version>
</dependency>

<dependency>
<groupId>junit</groupId>
Expand Down
1 change: 1 addition & 0 deletions retrofit-converters/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,6 @@
<modules>
<module>protobuf</module>
<module>jackson</module>
<module>wire</module>
</modules>
</project>
47 changes: 47 additions & 0 deletions retrofit-converters/wire/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
<?xml version="1.0" encoding="UTF-8"?>

<!--
~ Copyright 2013 Square, Inc.
-->

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>

<parent>
<groupId>com.squareup.retrofit</groupId>
<artifactId>retrofit-converters</artifactId>
<version>1.2.1-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

<artifactId>converter-wire</artifactId>
<name>Converter: Wire Protocol Buffers</name>

<dependencies>
<dependency>
<groupId>com.squareup.retrofit</groupId>
<artifactId>retrofit</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>com.squareup.wire</groupId>
<artifactId>wire-runtime</artifactId>
</dependency>

<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.easytesting</groupId>
<artifactId>fest-assert-core</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
// Copyright 2013 Square, Inc.
package retrofit.converter;

import com.squareup.wire.Message;
import com.squareup.wire.Wire;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.Type;
import retrofit.mime.TypedByteArray;
import retrofit.mime.TypedInput;
import retrofit.mime.TypedOutput;

/** A {@link Converter} that reads and writes protocol buffers using Wire. */
public class WireConverter implements Converter {
private static final String MIME_TYPE = "application/x-protobuf";

private final Wire wire;

public WireConverter(Wire wire) {
this.wire = wire;
}

@SuppressWarnings("unchecked") //
@Override public Object fromBody(TypedInput body, Type type) throws ConversionException {
if (!(type instanceof Class<?>)) {
throw new IllegalArgumentException("Expected a raw Class<?> but was " + type);
}
Class<?> c = (Class<?>) type;
if (!Message.class.isAssignableFrom(c)) {
throw new IllegalArgumentException("Expected a proto message but was " + c.getName());
}

if (!MIME_TYPE.equalsIgnoreCase(body.mimeType())) {
throw new IllegalArgumentException("Expected a proto but was: " + body.mimeType());
}

try {
byte[] data = consumeAsBytes(body.in());
return wire.parseFrom(data, (Class<Message>) c);
} catch (IOException e) {
throw new ConversionException(e);
}
}

@Override public TypedOutput toBody(Object object) {
if (!(object instanceof Message)) {
throw new IllegalArgumentException(
"Expected a proto message but was " + (object != null ? object.getClass().getName()
: "null"));
}
byte[] bytes = ((Message) object).toByteArray();
return new TypedByteArray(MIME_TYPE, bytes);
}

/** Reads a stream into a {@code byte} array. */
private byte[] consumeAsBytes(InputStream in) throws IOException {
ByteArrayOutputStream out = new ByteArrayOutputStream();
pipe(in, out);
return out.toByteArray();
}

/** Reads content from the given input and pipes it to the given output. */
private void pipe(InputStream in, OutputStream out) throws IOException {
byte[] buffer = new byte[4096];
int count;
while ((count = in.read(buffer)) != -1) {
out.write(buffer, 0, count);
}
}
}
210 changes: 210 additions & 0 deletions retrofit-converters/wire/src/test/java/retrofit/converter/Person.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,210 @@
// Copyright 2013 Square, Inc.

// Code generated by Wire protocol buffer compiler, do not edit.
// Source file: ../wire-runtime/src/test/proto/person.proto
package retrofit.converter;

import com.squareup.wire.Message;
import com.squareup.wire.ProtoEnum;
import com.squareup.wire.ProtoField;
import java.util.Collections;
import java.util.List;

import static com.squareup.wire.Message.Datatype.ENUM;
import static com.squareup.wire.Message.Datatype.INT32;
import static com.squareup.wire.Message.Datatype.STRING;
import static com.squareup.wire.Message.Label.REPEATED;
import static com.squareup.wire.Message.Label.REQUIRED;

public final class Person extends Message {

public static final String DEFAULT_NAME = "";
public static final Integer DEFAULT_ID = 0;
public static final String DEFAULT_EMAIL = "";
public static final List<PhoneNumber> DEFAULT_PHONE = Collections.emptyList();

/**
* The customer's full name.
*/
@ProtoField(tag = 1, type = STRING, label = REQUIRED)
public final String name;

/**
* The customer's ID number.
*/
@ProtoField(tag = 2, type = INT32, label = REQUIRED)
public final Integer id;

/**
* Email address for the customer.
*/
@ProtoField(tag = 3, type = STRING)
public final String email;

/**
* A list of the user's phone numbers.
*/
@ProtoField(tag = 4, label = REPEATED)
public final List<PhoneNumber> phone;

private Person(Builder builder) {
super(builder);
this.name = builder.name;
this.id = builder.id;
this.email = builder.email;
this.phone = immutableCopyOf(builder.phone);
}

@Override
public boolean equals(Object other) {
if (!(other instanceof Person)) return false;
Person o = (Person) other;
return equals(name, o.name)
&& equals(id, o.id)
&& equals(email, o.email)
&& equals(phone, o.phone);
}

@Override
public int hashCode() {
int result = hashCode;
if (result == 0) {
result = name != null ? name.hashCode() : 0;
result = result * 37 + (id != null ? id.hashCode() : 0);
result = result * 37 + (email != null ? email.hashCode() : 0);
result = result * 37 + (phone != null ? phone.hashCode() : 0);
hashCode = result;
}
return result;
}

public static final class Builder extends Message.Builder<Person> {

public String name;
public Integer id;
public String email;
public List<PhoneNumber> phone;

public Builder() {
}

public Builder(Person message) {
super(message);
if (message == null) return;
this.name = message.name;
this.id = message.id;
this.email = message.email;
this.phone = copyOf(message.phone);
}

public Builder name(String name) {
this.name = name;
return this;
}

public Builder id(Integer id) {
this.id = id;
return this;
}

public Builder email(String email) {
this.email = email;
return this;
}

public Builder phone(List<PhoneNumber> phone) {
this.phone = phone;
return this;
}

@Override
public Person build() {
checkRequiredFields();
return new Person(this);
}
}

public enum PhoneType {
@ProtoEnum(0)
MOBILE,
@ProtoEnum(1)
HOME,
@ProtoEnum(2)
WORK,
}

public static final class PhoneNumber extends Message {

public static final String DEFAULT_NUMBER = "";
public static final PhoneType DEFAULT_TYPE = PhoneType.HOME;

/**
* The user's phone number.
*/
@ProtoField(tag = 1, type = STRING, label = REQUIRED)
public final String number;

/**
* The type of phone stored here.
*/
@ProtoField(tag = 2, type = ENUM)
public final PhoneType type;

private PhoneNumber(Builder builder) {
super(builder);
this.number = builder.number;
this.type = builder.type;
}

@Override
public boolean equals(Object other) {
if (!(other instanceof PhoneNumber)) return false;
PhoneNumber o = (PhoneNumber) other;
return equals(number, o.number)
&& equals(type, o.type);
}

@Override
public int hashCode() {
int result = hashCode;
if (result == 0) {
result = number != null ? number.hashCode() : 0;
result = result * 37 + (type != null ? type.hashCode() : 0);
hashCode = result;
}
return result;
}

public static final class Builder extends Message.Builder<PhoneNumber> {

public String number;
public PhoneType type;

public Builder() {
}

public Builder(PhoneNumber message) {
super(message);
if (message == null) return;
this.number = message.number;
this.type = message.type;
}

public Builder number(String number) {
this.number = number;
return this;
}

public Builder type(PhoneType type) {
this.type = type;
return this;
}

@Override
public PhoneNumber build() {
checkRequiredFields();
return new PhoneNumber(this);
}
}
}
}
Loading

0 comments on commit c2e65d2

Please sign in to comment.