forked from square/retrofit
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request square#311 from square/jw/omar-comin-yo
Add a first-party converter for Wire.
- Loading branch information
Showing
6 changed files
with
421 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -17,5 +17,6 @@ | |
<modules> | ||
<module>protobuf</module> | ||
<module>jackson</module> | ||
<module>wire</module> | ||
</modules> | ||
</project> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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> |
72 changes: 72 additions & 0 deletions
72
retrofit-converters/wire/src/main/java/retrofit/converter/WireConverter.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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
210
retrofit-converters/wire/src/test/java/retrofit/converter/Person.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); | ||
} | ||
} | ||
} | ||
} |
Oops, something went wrong.