-
Notifications
You must be signed in to change notification settings - Fork 7.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add a first-party converter for Wire. #311
Merged
Merged
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@danrice-square Wire should have an API to read a Message off of an InputStream. This code is tedious and does an unnecessary copy