├── website └── static │ ├── icon-github.png │ ├── icon-square.png │ ├── logo-square.png │ ├── app-theme.css │ ├── jquery-maven-artifact.min.js │ ├── html5shiv.min.js │ ├── jquery.smooth-scroll.min.js │ └── app.css ├── .travis.yml ├── retrofit-converters ├── protobuf │ ├── src │ │ ├── test │ │ │ ├── gen-protos.sh │ │ │ ├── protos │ │ │ │ └── phone.proto │ │ │ └── java │ │ │ │ └── retrofit │ │ │ │ └── converter │ │ │ │ └── ProtoConverterTest.java │ │ └── main │ │ │ └── java │ │ │ └── retrofit │ │ │ └── converter │ │ │ └── ProtoConverter.java │ ├── README.md │ └── pom.xml ├── protobuf-nano │ ├── src │ │ ├── test │ │ │ ├── protos │ │ │ │ └── phone.proto │ │ │ └── java │ │ │ │ └── retrofit │ │ │ │ └── converter │ │ │ │ ├── PhoneProtos.java │ │ │ │ └── NanoProtoConverterTest.java │ │ └── main │ │ │ └── java │ │ │ └── retrofit │ │ │ └── converter │ │ │ └── NanoProtoConverter.java │ ├── README.md │ └── pom.xml ├── wire │ ├── README.md │ ├── pom.xml │ └── src │ │ ├── main │ │ └── java │ │ │ └── retrofit │ │ │ └── converter │ │ │ └── WireConverter.java │ │ └── test │ │ └── java │ │ └── retrofit │ │ └── converter │ │ └── WireConverterTest.java ├── jackson │ ├── README.md │ ├── pom.xml │ └── src │ │ ├── main │ │ └── java │ │ │ └── retrofit │ │ │ └── converter │ │ │ └── JacksonConverter.java │ │ └── test │ │ └── java │ │ └── retrofit │ │ └── converter │ │ └── JacksonConverterTest.java ├── README.md ├── simplexml │ ├── README.md │ ├── pom.xml │ └── src │ │ ├── main │ │ └── java │ │ │ └── retrofit │ │ │ └── converter │ │ │ └── SimpleXMLConverter.java │ │ └── test │ │ └── java │ │ └── retrofit │ │ └── converter │ │ └── SimpleXMLConverterTest.java └── pom.xml ├── retrofit ├── src │ ├── main │ │ └── java │ │ │ └── retrofit │ │ │ ├── http │ │ │ ├── package-info.java │ │ │ ├── RestMethod.java │ │ │ ├── GET.java │ │ │ ├── HEAD.java │ │ │ ├── DELETE.java │ │ │ ├── PUT.java │ │ │ ├── POST.java │ │ │ ├── PATCH.java │ │ │ ├── Multipart.java │ │ │ ├── Streaming.java │ │ │ ├── Path.java │ │ │ ├── EncodedQueryMap.java │ │ │ ├── EncodedQuery.java │ │ │ ├── FormUrlEncoded.java │ │ │ ├── EncodedPath.java │ │ │ ├── Header.java │ │ │ ├── Headers.java │ │ │ ├── FieldMap.java │ │ │ ├── QueryMap.java │ │ │ ├── Body.java │ │ │ ├── PartMap.java │ │ │ ├── Part.java │ │ │ ├── Field.java │ │ │ └── Query.java │ │ │ ├── client │ │ │ ├── Defaults.java │ │ │ ├── OkClient.java │ │ │ ├── Client.java │ │ │ ├── Header.java │ │ │ ├── Request.java │ │ │ ├── Response.java │ │ │ └── UrlConnectionClient.java │ │ │ ├── package-info.java │ │ │ ├── Endpoint.java │ │ │ ├── android │ │ │ ├── AndroidLog.java │ │ │ ├── MainThreadExecutor.java │ │ │ └── AndroidApacheClient.java │ │ │ ├── Endpoints.java │ │ │ ├── converter │ │ │ ├── ConversionException.java │ │ │ ├── Converter.java │ │ │ └── GsonConverter.java │ │ │ ├── ResponseCallback.java │ │ │ ├── ResponseWrapper.java │ │ │ ├── mime │ │ │ ├── TypedOutput.java │ │ │ ├── TypedInput.java │ │ │ ├── MimeUtil.java │ │ │ ├── TypedString.java │ │ │ ├── FormUrlEncodedTypedOutput.java │ │ │ ├── TypedByteArray.java │ │ │ └── TypedFile.java │ │ │ ├── RequestInterceptor.java │ │ │ ├── Callback.java │ │ │ ├── ErrorHandler.java │ │ │ ├── CallbackRunnable.java │ │ │ ├── RxSupport.java │ │ │ ├── RequestInterceptorTape.java │ │ │ ├── Profiler.java │ │ │ ├── ExceptionCatchingTypedInput.java │ │ │ ├── appengine │ │ │ └── UrlFetchClient.java │ │ │ ├── RetrofitError.java │ │ │ └── Utils.java │ └── test │ │ └── java │ │ └── retrofit │ │ ├── mime │ │ ├── MimeHelper.java │ │ ├── TypedByteArrayTest.java │ │ ├── MimeUtilTest.java │ │ ├── TypedFileTest.java │ │ ├── FormUrlEncodingTypedOutputTest.java │ │ └── MultipartTypedOutputTest.java │ │ ├── EndpointsTest.java │ │ ├── TestingUtils.java │ │ ├── CallbackRunnableTest.java │ │ ├── client │ │ ├── ClientIntegrationTest.java │ │ └── DummyHttpUrlConnection.java │ │ └── ErrorHandlerTest.java └── pom.xml ├── .gitignore ├── retrofit-mock ├── src │ └── main │ │ └── java │ │ └── retrofit │ │ ├── MockHttpRetrofitError.java │ │ ├── MockTypedInput.java │ │ ├── android │ │ └── AndroidMockValuePersistence.java │ │ └── MockHttpException.java └── pom.xml ├── CONTRIBUTING.md ├── retrofit-samples ├── pom.xml ├── github-client │ ├── pom.xml │ └── src │ │ └── main │ │ └── java │ │ └── com │ │ └── example │ │ └── retrofit │ │ └── GitHubClient.java └── mock-github-client │ └── pom.xml ├── deploy_website.sh └── README.md /website/static/icon-github.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/google/retrofit/HEAD/website/static/icon-github.png -------------------------------------------------------------------------------- /website/static/icon-square.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/google/retrofit/HEAD/website/static/icon-square.png -------------------------------------------------------------------------------- /website/static/logo-square.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/google/retrofit/HEAD/website/static/logo-square.png -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: java 2 | 3 | branches: 4 | except: 5 | - gh-pages 6 | 7 | notifications: 8 | email: false 9 | -------------------------------------------------------------------------------- /retrofit-converters/protobuf/src/test/gen-protos.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -ex 4 | protoc --java_out=java/ protos/phone.proto 5 | -------------------------------------------------------------------------------- /retrofit/src/main/java/retrofit/http/package-info.java: -------------------------------------------------------------------------------- 1 | // Copyright 2014 Square, Inc. 2 | 3 | /** Annotations for interface methods to control the HTTP request behavior. */ 4 | package retrofit.http; 5 | -------------------------------------------------------------------------------- /retrofit-converters/protobuf/src/test/protos/phone.proto: -------------------------------------------------------------------------------- 1 | package retrofit; 2 | 3 | option java_package = "retrofit.converter"; 4 | option java_outer_classname = "PhoneProtos"; 5 | 6 | message Phone { 7 | optional string number = 1; 8 | } 9 | -------------------------------------------------------------------------------- /retrofit-converters/protobuf/README.md: -------------------------------------------------------------------------------- 1 | Google Protocol Buffer Converter 2 | ================================ 3 | 4 | A `Converter` which uses [Protocol Buffer][1] binary serialization. 5 | 6 | 7 | [1]: https://developers.google.com/protocol-buffers/ 8 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .classpath 2 | .project 3 | .settings 4 | eclipsebin 5 | 6 | bin 7 | gen 8 | build 9 | out 10 | lib 11 | 12 | target 13 | pom.xml.* 14 | release.properties 15 | 16 | .idea 17 | *.iml 18 | classes 19 | 20 | obj 21 | 22 | .DS_Store 23 | -------------------------------------------------------------------------------- /retrofit-converters/protobuf-nano/src/test/protos/phone.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto2"; 2 | 3 | package retrofit; 4 | 5 | option java_package = "retrofit.converter"; 6 | option java_outer_classname = "PhoneProtos"; 7 | 8 | message Phone { 9 | optional string number = 1; 10 | } 11 | -------------------------------------------------------------------------------- /retrofit/src/main/java/retrofit/client/Defaults.java: -------------------------------------------------------------------------------- 1 | package retrofit.client; 2 | 3 | final class Defaults { 4 | static final int CONNECT_TIMEOUT_MILLIS = 15 * 1000; // 15s 5 | static final int READ_TIMEOUT_MILLIS = 20 * 1000; // 20s 6 | 7 | private Defaults() { 8 | // No instances. 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /retrofit/src/main/java/retrofit/package-info.java: -------------------------------------------------------------------------------- 1 | // Copyright 2014 Square, Inc. 2 | 3 | /** 4 | * Retrofit turns your REST API into a Java interface. 5 | *
 6 |  * public interface GitHubService {
 7 |  *   @GET("/users/{user}/repos")
 8 |  *   List<Repo> listRepos(@Path("user") String user);
 9 |  * }
10 |  * 
11 | */ 12 | package retrofit; 13 | -------------------------------------------------------------------------------- /retrofit-converters/wire/README.md: -------------------------------------------------------------------------------- 1 | Wire Converter 2 | ============== 3 | 4 | A `Converter` which uses [Wire][1] for protocol buffer-compatible serialization. 5 | 6 | A default `Wire` instance will be created or one can be configured and passed to the 7 | `WireConverter` construction to further control the serialization. 8 | 9 | 10 | [1]: https://github.com/square/wire 11 | -------------------------------------------------------------------------------- /retrofit-converters/jackson/README.md: -------------------------------------------------------------------------------- 1 | Jackson Converter 2 | ================= 3 | 4 | A `Converter` which uses [Jackson][1] for serialization to and from JSON. 5 | 6 | A default `ObjectMapper` instance will be created or one can be configured and passed to the 7 | `JacksonConverter` construction to further control the serialization. 8 | 9 | 10 | [1]: http://wiki.fasterxml.com/JacksonHome 11 | -------------------------------------------------------------------------------- /retrofit/src/test/java/retrofit/mime/MimeHelper.java: -------------------------------------------------------------------------------- 1 | // Copyright 2013 Square, Inc. 2 | package retrofit.mime; 3 | 4 | import java.util.List; 5 | 6 | public class MimeHelper { 7 | public static List getParts(MultipartTypedOutput output) { 8 | try { 9 | return output.getParts(); 10 | } catch (Exception e) { 11 | throw new RuntimeException(e); 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /retrofit/src/main/java/retrofit/Endpoint.java: -------------------------------------------------------------------------------- 1 | package retrofit; 2 | 3 | /** 4 | * Represents an API endpoint URL and associated name. Callers should always consult the instance 5 | * for the latest values rather than caching the returned values. 6 | * 7 | * @author Matt Hickman (mhickman@palantir.com) 8 | */ 9 | public interface Endpoint { 10 | 11 | /** The base API URL. */ 12 | String getUrl(); 13 | 14 | /** A name for differentiating between multiple API URLs. */ 15 | String getName(); 16 | 17 | } 18 | -------------------------------------------------------------------------------- /retrofit-converters/README.md: -------------------------------------------------------------------------------- 1 | Retrofit Converters 2 | =================== 3 | 4 | Retrofit ships with a default converter for JSON that uses Gson but the library is content-format 5 | agnostic. The child modules contained herein are additional converters for other popular formats. 6 | 7 | To use, supply an instance of your desired converter when building your `RestAdapter` instance. 8 | 9 | ```java 10 | RestAdapter restAdapter = new RestAdapter.Builder() 11 | .setEndpoint("https://api.example.com") 12 | .setConverter(new ProtoConverter()) 13 | .build(); 14 | ``` 15 | -------------------------------------------------------------------------------- /retrofit-converters/simplexml/README.md: -------------------------------------------------------------------------------- 1 | Simple XML Converter 2 | ==================== 3 | 4 | A `Converter` which uses [Simple][1] for XML serialization. 5 | 6 | A default `Serializer` instance will be created or one can be configured and passed to the 7 | `SimpleXMLConverter` construction to further control the serialization. 8 | 9 | 10 | Android 11 | ------- 12 | 13 | Simple depends on artifacts which are already provided by the Android platform. When specifying as 14 | a Maven or Gradle dependency, exclude the following transitive dependencies: `stax:stax-api`, 15 | `stax:stax`, and `xpp3:xpp3`. 16 | 17 | 18 | 19 | [1]: http://simple.sourceforge.net/ 20 | -------------------------------------------------------------------------------- /retrofit-mock/src/main/java/retrofit/MockHttpRetrofitError.java: -------------------------------------------------------------------------------- 1 | // Copyright 2013 Square, Inc. 2 | package retrofit; 3 | 4 | import java.lang.reflect.Type; 5 | import retrofit.client.Response; 6 | 7 | class MockHttpRetrofitError extends RetrofitError { 8 | private final Object body; 9 | 10 | MockHttpRetrofitError(String message, String url, Response response, Object body, 11 | Type responseType) { 12 | super(message, url, response, null, responseType, false, null); 13 | this.body = body; 14 | } 15 | 16 | @Override public Object getBody() { 17 | return body; 18 | } 19 | 20 | @Override public Object getBodyAs(Type type) { 21 | return body; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /retrofit/src/test/java/retrofit/EndpointsTest.java: -------------------------------------------------------------------------------- 1 | // Copyright 2014 Square, Inc. 2 | package retrofit; 3 | 4 | import org.junit.Test; 5 | 6 | import static org.assertj.core.api.Assertions.assertThat; 7 | 8 | public class EndpointsTest { 9 | @Test public void endpointOnly() { 10 | Endpoint endpoint = Endpoints.newFixedEndpoint("http://example.com"); 11 | assertThat(endpoint.getUrl()).isEqualTo("http://example.com"); 12 | } 13 | 14 | @Test public void endpointAndName() { 15 | Endpoint endpoint = Endpoints.newFixedEndpoint("http://example.com", "production"); 16 | assertThat(endpoint.getUrl()).isEqualTo("http://example.com"); 17 | assertThat(endpoint.getName()).isEqualTo("production"); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /retrofit-converters/protobuf-nano/README.md: -------------------------------------------------------------------------------- 1 | Google Nano Protocol Buffer Converter 2 | ===================================== 3 | 4 | A `Converter` which uses [Nano Protocol Buffer][1] binary serialization. 5 | 6 | To build this module, you will need to [install][2] the Android external\_protobuf module. 7 | 8 | To use the converter, depend on the `nano` classifier: 9 | 10 | ```xml 11 | 12 | com.squareup.retrofit 13 | retrofit-converters 14 | nano 15 | 16 | ``` 17 | 18 | [1]: https://github.com/android/platform_external_protobuf/tree/master/java/src/main/java/com/google/protobuf/nano 19 | [2]: https://github.com/android/platform_external_protobuf/blob/master/java/README.txt 20 | -------------------------------------------------------------------------------- /retrofit/src/test/java/retrofit/mime/TypedByteArrayTest.java: -------------------------------------------------------------------------------- 1 | // Copyright 2010 Square, Inc. 2 | package retrofit.mime; 3 | 4 | import org.junit.Test; 5 | 6 | import static org.assertj.core.api.Assertions.assertThat; 7 | 8 | public class TypedByteArrayTest { 9 | private static final String GIF = "image/gif"; 10 | 11 | @Test public void objectEquals() { 12 | TypedByteArray a1 = new TypedByteArray(GIF, new byte[] { 10, 20 }); 13 | TypedByteArray a2 = new TypedByteArray(GIF, new byte[] { 10, 20 }); 14 | TypedByteArray b = new TypedByteArray(GIF, new byte[] { 8, 12 }); 15 | 16 | assertThat(a1).isEqualTo(a2); 17 | assertThat(a1.hashCode()).isEqualTo(a2.hashCode()); 18 | assertThat(a1).isNotEqualTo(b); 19 | assertThat(a1.hashCode()).isNotEqualTo(b.hashCode()); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | Contributing 2 | ============ 3 | 4 | If you would like to contribute code to Retrofit you can do so through GitHub by 5 | forking the repository and sending a pull request. 6 | 7 | When submitting code, please make every effort to follow existing conventions 8 | and style in order to keep the code as readable as possible. Please also make 9 | sure your code compiles by running `mvn clean verify`. Checkstyle failures 10 | during compilation indicate errors in your style and can be viewed in the 11 | `checkstyle-result.xml` file. 12 | 13 | Before your code can be accepted into the project you must also sign the 14 | [Individual Contributor License Agreement (CLA)][1]. 15 | 16 | 17 | [1]: https://spreadsheets.google.com/spreadsheet/viewform?formkey=dDViT2xzUHAwRkI3X3k5Z0lQM091OGc6MQ&ndplr=1 18 | -------------------------------------------------------------------------------- /retrofit-samples/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 4.0.0 5 | 6 | 7 | com.squareup.retrofit 8 | parent 9 | 1.6.2-SNAPSHOT 10 | ../pom.xml 11 | 12 | 13 | com.squareup.retrofit.samples 14 | parent 15 | Samples 16 | pom 17 | 18 | 19 | github-client 20 | mock-github-client 21 | 22 | 23 | -------------------------------------------------------------------------------- /retrofit-samples/github-client/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 4.0.0 5 | 6 | 7 | com.squareup.retrofit.samples 8 | parent 9 | 1.6.2-SNAPSHOT 10 | ../pom.xml 11 | 12 | 13 | github-client 14 | Sample: GitHub Client 15 | 16 | 17 | 18 | com.squareup.retrofit 19 | retrofit 20 | ${project.version} 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /retrofit/src/main/java/retrofit/android/AndroidLog.java: -------------------------------------------------------------------------------- 1 | package retrofit.android; 2 | 3 | import android.util.Log; 4 | import retrofit.RestAdapter; 5 | 6 | /** A {@link RestAdapter.Log logger} for Android. */ 7 | public class AndroidLog implements RestAdapter.Log { 8 | private static final int LOG_CHUNK_SIZE = 4000; 9 | 10 | private final String tag; 11 | 12 | public AndroidLog(String tag) { 13 | this.tag = tag; 14 | } 15 | 16 | @Override public final void log(String message) { 17 | for (int i = 0, len = message.length(); i < len; i += LOG_CHUNK_SIZE) { 18 | int end = Math.min(len, i + LOG_CHUNK_SIZE); 19 | logChunk(message.substring(i, end)); 20 | } 21 | } 22 | 23 | /** 24 | * Called one or more times for each call to {@link #log(String)}. The length of {@code chunk} 25 | * will be no more than 4000 characters to support Android's {@link Log} class. 26 | */ 27 | public void logChunk(String chunk) { 28 | Log.d(getTag(), chunk); 29 | } 30 | 31 | public String getTag() { 32 | return tag; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /deploy_website.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -ex 4 | 5 | REPO="git@github.com:square/retrofit.git" 6 | GROUP_ID="com.squareup.retrofit" 7 | ARTIFACT_ID="retrofit" 8 | 9 | DIR=temp-clone 10 | 11 | # Delete any existing temporary website clone 12 | rm -rf $DIR 13 | 14 | # Clone the current repo into temp folder 15 | git clone $REPO $DIR 16 | 17 | # Move working directory into temp folder 18 | cd $DIR 19 | 20 | # Checkout and track the gh-pages branch 21 | git checkout -t origin/gh-pages 22 | 23 | # Delete everything 24 | rm -rf * 25 | 26 | # Copy website files from real repo 27 | cp -R ../website/* . 28 | 29 | # Download the latest javadoc 30 | curl -L "http://repository.sonatype.org/service/local/artifact/maven/redirect?r=central-proxy&g=$GROUP_ID&a=$ARTIFACT_ID&v=LATEST&c=javadoc" > javadoc.zip 31 | mkdir javadoc 32 | unzip javadoc.zip -d javadoc 33 | rm javadoc.zip 34 | 35 | # Stage all files in git and create a commit 36 | git add . 37 | git add -u 38 | git commit -m "Website at $(date)" 39 | 40 | # Push the new files up to GitHub 41 | git push origin gh-pages 42 | 43 | # Delete our temp folder 44 | cd .. 45 | rm -rf $DIR 46 | -------------------------------------------------------------------------------- /retrofit-samples/mock-github-client/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | 4.0.0 9 | 10 | 11 | com.squareup.retrofit.samples 12 | parent 13 | 1.6.2-SNAPSHOT 14 | ../pom.xml 15 | 16 | 17 | mock-github-client 18 | Sample: Mock GitHub Client 19 | 20 | 21 | 22 | com.squareup.retrofit 23 | retrofit 24 | ${project.version} 25 | 26 | 27 | com.squareup.retrofit 28 | retrofit-mock 29 | ${project.version} 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /retrofit/src/main/java/retrofit/android/MainThreadExecutor.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2013 Square, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package retrofit.android; 17 | 18 | import android.os.Handler; 19 | import android.os.Looper; 20 | 21 | import java.util.concurrent.Executor; 22 | 23 | /** Executor that runs tasks on Android's main thread. */ 24 | public final class MainThreadExecutor implements Executor { 25 | private final Handler handler = new Handler(Looper.getMainLooper()); 26 | 27 | @Override public void execute(Runnable r) { 28 | handler.post(r); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /retrofit/src/main/java/retrofit/Endpoints.java: -------------------------------------------------------------------------------- 1 | package retrofit; 2 | 3 | /** 4 | * Static factory methods for creating {@link Endpoint} instances. 5 | * 6 | * @author Matt Hickman (mhickman@palantir.com) 7 | */ 8 | public final class Endpoints { 9 | private static final String DEFAULT_NAME = "default"; 10 | 11 | private Endpoints() { 12 | } 13 | 14 | /** Create a server with the provided URL. */ 15 | public static Endpoint newFixedEndpoint(String url) { 16 | return new FixedEndpoint(url, DEFAULT_NAME); 17 | } 18 | 19 | /** Create an endpoint with the provided URL and name. */ 20 | public static Endpoint newFixedEndpoint(String url, String name) { 21 | return new FixedEndpoint(url, name); 22 | } 23 | 24 | private static class FixedEndpoint implements Endpoint { 25 | private final String apiUrl; 26 | private final String name; 27 | 28 | FixedEndpoint(String apiUrl, String name) { 29 | this.apiUrl = apiUrl; 30 | this.name = name; 31 | } 32 | 33 | @Override public String getUrl() { 34 | return apiUrl; 35 | } 36 | 37 | @Override public String getName() { 38 | return name; 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /retrofit/src/main/java/retrofit/http/RestMethod.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2013 Square, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package retrofit.http; 17 | 18 | import java.lang.annotation.Documented; 19 | import java.lang.annotation.Retention; 20 | import java.lang.annotation.Target; 21 | 22 | import static java.lang.annotation.ElementType.ANNOTATION_TYPE; 23 | import static java.lang.annotation.RetentionPolicy.RUNTIME; 24 | 25 | @Documented 26 | @Target(ANNOTATION_TYPE) 27 | @Retention(RUNTIME) 28 | public @interface RestMethod { 29 | String value(); 30 | boolean hasBody() default false; 31 | } 32 | -------------------------------------------------------------------------------- /retrofit/src/main/java/retrofit/http/GET.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2013 Square, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package retrofit.http; 17 | 18 | import java.lang.annotation.Documented; 19 | import java.lang.annotation.Retention; 20 | import java.lang.annotation.Target; 21 | 22 | import static java.lang.annotation.ElementType.METHOD; 23 | import static java.lang.annotation.RetentionPolicy.RUNTIME; 24 | 25 | /** Make a GET request to a REST path relative to base URL. */ 26 | @Documented 27 | @Target(METHOD) 28 | @Retention(RUNTIME) 29 | @RestMethod("GET") 30 | public @interface GET { 31 | String value(); 32 | } 33 | -------------------------------------------------------------------------------- /retrofit/src/main/java/retrofit/http/HEAD.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2013 Square, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package retrofit.http; 17 | 18 | import java.lang.annotation.Documented; 19 | import java.lang.annotation.Retention; 20 | import java.lang.annotation.Target; 21 | 22 | import static java.lang.annotation.ElementType.METHOD; 23 | import static java.lang.annotation.RetentionPolicy.RUNTIME; 24 | 25 | /** Make a HEAD request to a REST path relative to base URL. */ 26 | @Documented 27 | @Target(METHOD) 28 | @Retention(RUNTIME) 29 | @RestMethod("HEAD") 30 | public @interface HEAD { 31 | String value(); 32 | } 33 | -------------------------------------------------------------------------------- /retrofit/src/main/java/retrofit/http/DELETE.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2013 Square, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package retrofit.http; 17 | 18 | import java.lang.annotation.Documented; 19 | import java.lang.annotation.Retention; 20 | import java.lang.annotation.Target; 21 | 22 | import static java.lang.annotation.ElementType.METHOD; 23 | import static java.lang.annotation.RetentionPolicy.RUNTIME; 24 | 25 | /** Make a DELETE request to a REST path relative to base URL. */ 26 | @Documented 27 | @Target(METHOD) 28 | @Retention(RUNTIME) 29 | @RestMethod("DELETE") 30 | public @interface DELETE { 31 | String value(); 32 | } 33 | -------------------------------------------------------------------------------- /retrofit/src/test/java/retrofit/TestingUtils.java: -------------------------------------------------------------------------------- 1 | // Copyright 2013 Square, Inc. 2 | package retrofit; 3 | 4 | import java.io.IOException; 5 | import java.lang.reflect.Method; 6 | import java.util.Map; 7 | import retrofit.mime.MultipartTypedOutput; 8 | import retrofit.mime.TypedOutput; 9 | 10 | import static org.assertj.core.api.Assertions.assertThat; 11 | 12 | public abstract class TestingUtils { 13 | public static Method getMethod(Class c, String name) { 14 | for (Method method : c.getDeclaredMethods()) { 15 | if (method.getName().equals(name)) { 16 | return method; 17 | } 18 | } 19 | throw new IllegalArgumentException("Unknown method '" + name + "' on " + c); 20 | } 21 | 22 | public static TypedOutput createMultipart(Map parts) { 23 | MultipartTypedOutput typedOutput = new MultipartTypedOutput(); 24 | for (Map.Entry part : parts.entrySet()) { 25 | typedOutput.addPart(part.getKey(), part.getValue()); 26 | } 27 | return typedOutput; 28 | } 29 | 30 | public static void assertBytes(byte[] bytes, String expected) throws IOException { 31 | assertThat(new String(bytes, "UTF-8")).isEqualTo(expected); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /retrofit/src/main/java/retrofit/http/PUT.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2013 Square, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package retrofit.http; 17 | 18 | import java.lang.annotation.Documented; 19 | import java.lang.annotation.Retention; 20 | import java.lang.annotation.Target; 21 | 22 | import static java.lang.annotation.ElementType.METHOD; 23 | import static java.lang.annotation.RetentionPolicy.RUNTIME; 24 | 25 | /** Make a PUT request to a REST path relative to base URL. */ 26 | @Documented 27 | @Target(METHOD) 28 | @Retention(RUNTIME) 29 | @RestMethod(value = "PUT", hasBody = true) 30 | public @interface PUT { 31 | String value(); 32 | } 33 | -------------------------------------------------------------------------------- /website/static/app-theme.css: -------------------------------------------------------------------------------- 1 | /* http://www.colorhexa.com/48b982 */ 2 | 3 | /*** Primary ***/ 4 | 5 | header, 6 | #subtitle, 7 | a.dl { 8 | background-color: #48b983; 9 | } 10 | 11 | .content-nav li.active a, 12 | .content-nav li.active a:hover { 13 | border-left-color: #48b983; 14 | } 15 | 16 | /*** One step left on the monochromatic scale ***/ 17 | 18 | header menu li a:hover, 19 | a.dl:hover { 20 | background-color: #40a776; 21 | } 22 | a { 23 | color: #40a776; 24 | } 25 | 26 | /*** Three steps left on the monochromatic scale ***/ 27 | 28 | a:hover { 29 | color: #32835c; 30 | } 31 | 32 | 33 | /****************************************************************\ 34 | **** Syntax highlighting styles ******************************** 35 | \****************************************************************/ 36 | 37 | .pln { color: #000; } 38 | .str { color: #32835b; } 39 | .kwd { color: #666; } 40 | .com { color: #800; } 41 | .typ { color: #222; } 42 | .lit { color: #666; } 43 | .pun { color: #888; } 44 | .opn { color: #888; } 45 | .clo { color: #888; } 46 | .tag { color: #32835b; } 47 | .atn { color: #606; } 48 | .atv { color: #080; } 49 | .dec { color: #606; } 50 | .var { color: #606; } 51 | .fun { color: #f00; } 52 | -------------------------------------------------------------------------------- /retrofit/src/main/java/retrofit/http/POST.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2013 Square, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package retrofit.http; 17 | 18 | import java.lang.annotation.Documented; 19 | import java.lang.annotation.Retention; 20 | import java.lang.annotation.Target; 21 | 22 | import static java.lang.annotation.ElementType.METHOD; 23 | import static java.lang.annotation.RetentionPolicy.RUNTIME; 24 | 25 | /** Make a POST request to a REST path relative to base URL. */ 26 | @Documented 27 | @Target(METHOD) 28 | @Retention(RUNTIME) 29 | @RestMethod(value = "POST", hasBody = true) 30 | public @interface POST { 31 | String value(); 32 | } 33 | -------------------------------------------------------------------------------- /retrofit/src/main/java/retrofit/http/PATCH.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2013 Square, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package retrofit.http; 17 | 18 | import java.lang.annotation.Documented; 19 | import java.lang.annotation.Retention; 20 | import java.lang.annotation.Target; 21 | 22 | import static java.lang.annotation.ElementType.METHOD; 23 | import static java.lang.annotation.RetentionPolicy.RUNTIME; 24 | 25 | /** Make a PATCH request to a REST path relative to base URL. */ 26 | @Documented 27 | @Target(METHOD) 28 | @Retention(RUNTIME) 29 | @RestMethod(value = "PATCH", hasBody = true) 30 | public @interface PATCH { 31 | String value(); 32 | } 33 | -------------------------------------------------------------------------------- /retrofit/src/main/java/retrofit/converter/ConversionException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2013 Square, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package retrofit.converter; 17 | 18 | /** Indicate that conversion was unable to complete successfully. */ 19 | @SuppressWarnings("UnusedDeclaration") 20 | public class ConversionException extends Exception { 21 | public ConversionException(String message) { 22 | super(message); 23 | } 24 | 25 | public ConversionException(String message, Throwable throwable) { 26 | super(message, throwable); 27 | } 28 | 29 | public ConversionException(Throwable throwable) { 30 | super(throwable); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /retrofit/src/main/java/retrofit/ResponseCallback.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2013 Square, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package retrofit; 17 | 18 | import retrofit.client.Response; 19 | 20 | /** 21 | * An extension of {@link Callback} which returns only {@link Response} object 22 | * in {@link Callback#success(Object, retrofit.client.Response)} method. 23 | */ 24 | public abstract class ResponseCallback implements Callback { 25 | 26 | @Override public void success(Response response, Response response2) { 27 | success(response); 28 | } 29 | 30 | /** Successful HTTP response. */ 31 | public abstract void success(Response response); 32 | } 33 | -------------------------------------------------------------------------------- /retrofit/src/main/java/retrofit/http/Multipart.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2013 Square, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package retrofit.http; 17 | 18 | import java.lang.annotation.Documented; 19 | import java.lang.annotation.Retention; 20 | import java.lang.annotation.Target; 21 | 22 | import static java.lang.annotation.ElementType.METHOD; 23 | import static java.lang.annotation.RetentionPolicy.RUNTIME; 24 | 25 | /** 26 | * Denotes that the request body is multi-part. Parts should be declared as parameters and 27 | * annotated with {@link Part @Part}. 28 | */ 29 | @Documented 30 | @Target(METHOD) 31 | @Retention(RUNTIME) 32 | public @interface Multipart { 33 | } 34 | -------------------------------------------------------------------------------- /retrofit/src/main/java/retrofit/ResponseWrapper.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2013 Square, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package retrofit; 17 | 18 | import retrofit.client.Response; 19 | 20 | /** 21 | * A wrapper that holds the {@link Response} and {@link retrofit.converter.Converter} response to 22 | * be used by the {@link CallbackRunnable} for success method calls on {@link Callback}. 23 | * 24 | * @author JJ Ford (jj.n.ford@gmail.com) 25 | */ 26 | final class ResponseWrapper { 27 | final Response response; 28 | final Object responseBody; 29 | 30 | ResponseWrapper(Response response, Object responseBody) { 31 | this.response = response; 32 | this.responseBody = responseBody; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /retrofit/src/main/java/retrofit/http/Streaming.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2014 Square, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package retrofit.http; 17 | 18 | import java.lang.annotation.Documented; 19 | import java.lang.annotation.Retention; 20 | import java.lang.annotation.Target; 21 | 22 | import static java.lang.annotation.ElementType.METHOD; 23 | import static java.lang.annotation.RetentionPolicy.RUNTIME; 24 | 25 | /** 26 | * Treat the response body on methods returning {@link retrofit.client.Response Response} as is, 27 | * i.e. without converting {@link retrofit.client.Response#getBody() getBody()} to {@code byte[]}. 28 | */ 29 | @Documented 30 | @Target(METHOD) 31 | @Retention(RUNTIME) 32 | public @interface Streaming { 33 | } 34 | -------------------------------------------------------------------------------- /retrofit-converters/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 4.0.0 5 | 6 | 7 | com.squareup.retrofit 8 | parent 9 | 1.6.2-SNAPSHOT 10 | ../pom.xml 11 | 12 | 13 | retrofit-converters 14 | Converters 15 | pom 16 | 17 | 18 | protobuf 19 | jackson 20 | wire 21 | simplexml 22 | 23 | 24 | 25 | 26 | nano 27 | 28 | protobuf-nano 29 | 30 | 31 | 32 | 33 | maven-jar-plugin 34 | 35 | nano 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /retrofit-mock/src/main/java/retrofit/MockTypedInput.java: -------------------------------------------------------------------------------- 1 | // Copyright 2013 Square, Inc. 2 | package retrofit; 3 | 4 | import java.io.ByteArrayInputStream; 5 | import java.io.ByteArrayOutputStream; 6 | import java.io.IOException; 7 | import java.io.InputStream; 8 | import retrofit.converter.Converter; 9 | import retrofit.mime.TypedInput; 10 | 11 | class MockTypedInput implements TypedInput { 12 | private final Converter converter; 13 | private final Object body; 14 | 15 | private byte[] bytes; 16 | 17 | MockTypedInput(Converter converter, Object body) { 18 | this.converter = converter; 19 | this.body = body; 20 | } 21 | 22 | @Override public String mimeType() { 23 | return "application/unknown"; 24 | } 25 | 26 | @Override public long length() { 27 | try { 28 | initBytes(); 29 | } catch (IOException e) { 30 | throw new RuntimeException(e); 31 | } 32 | return bytes.length; 33 | } 34 | 35 | @Override public InputStream in() throws IOException { 36 | initBytes(); 37 | return new ByteArrayInputStream(bytes); 38 | } 39 | 40 | private synchronized void initBytes() throws IOException { 41 | if (bytes == null) { 42 | ByteArrayOutputStream out = new ByteArrayOutputStream(); 43 | converter.toBody(body).writeTo(out); 44 | bytes = out.toByteArray(); 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /retrofit/src/main/java/retrofit/mime/TypedOutput.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2013 Square, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package retrofit.mime; 17 | 18 | import java.io.IOException; 19 | import java.io.OutputStream; 20 | 21 | /** 22 | * Binary data with an associated mime type. 23 | * 24 | * @author Bob Lee (bob@squareup.com) 25 | */ 26 | public interface TypedOutput { 27 | /** Original filename. 28 | * 29 | * Used only for multipart requests, may be null. */ 30 | String fileName(); 31 | 32 | /** Returns the mime type. */ 33 | String mimeType(); 34 | 35 | /** Length in bytes or -1 if unknown. */ 36 | long length(); 37 | 38 | /** Writes these bytes to the given output stream. */ 39 | void writeTo(OutputStream out) throws IOException; 40 | } 41 | -------------------------------------------------------------------------------- /retrofit/src/main/java/retrofit/mime/TypedInput.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2013 Square, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package retrofit.mime; 17 | 18 | import java.io.IOException; 19 | import java.io.InputStream; 20 | 21 | /** 22 | * Binary data with an associated mime type. 23 | * 24 | * @author Jake Wharton (jw@squareup.com) 25 | */ 26 | public interface TypedInput { 27 | 28 | /** Returns the mime type. */ 29 | String mimeType(); 30 | 31 | /** Length in bytes. Returns {@code -1} if length is unknown. */ 32 | long length(); 33 | 34 | /** 35 | * Read bytes as stream. Unless otherwise specified, this method may only be called once. It is 36 | * the responsibility of the caller to close the stream. 37 | */ 38 | InputStream in() throws IOException; 39 | } 40 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Retrofit 2 | ======== 3 | 4 | Type-safe REST client for Android and Java by Square, Inc. 5 | 6 | For more information please see [the website][1]. 7 | 8 | 9 | Download 10 | -------- 11 | 12 | Download [the latest JAR][2] or grab via Maven: 13 | ```xml 14 | 15 | com.squareup.retrofit 16 | retrofit 17 | 1.6.1 18 | 19 | ``` 20 | or Gradle: 21 | ```groovy 22 | compile 'com.squareup.retrofit:retrofit:1.6.1' 23 | ``` 24 | 25 | 26 | 27 | License 28 | ======= 29 | 30 | Copyright 2013 Square, Inc. 31 | 32 | Licensed under the Apache License, Version 2.0 (the "License"); 33 | you may not use this file except in compliance with the License. 34 | You may obtain a copy of the License at 35 | 36 | http://www.apache.org/licenses/LICENSE-2.0 37 | 38 | Unless required by applicable law or agreed to in writing, software 39 | distributed under the License is distributed on an "AS IS" BASIS, 40 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 41 | See the License for the specific language governing permissions and 42 | limitations under the License. 43 | 44 | 45 | [1]: http://square.github.io/retrofit/ 46 | [2]: http://repository.sonatype.org/service/local/artifact/maven/redirect?r=central-proxy&g=com.squareup.retrofit&a=retrofit&v=LATEST 47 | -------------------------------------------------------------------------------- /retrofit/src/main/java/retrofit/android/AndroidApacheClient.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2013 Square, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package retrofit.android; 17 | 18 | import android.net.http.AndroidHttpClient; 19 | import retrofit.client.ApacheClient; 20 | 21 | /** 22 | * Provides a {@link retrofit.client.Client} which uses the Android-specific version of 23 | * {@link org.apache.http.client.HttpClient}, {@link AndroidHttpClient}. 24 | *

25 | * If you need to provide a customized version of the {@link AndroidHttpClient} or a different 26 | * {@link org.apache.http.client.HttpClient} on Android use {@link ApacheClient} directly. 27 | */ 28 | public final class AndroidApacheClient extends ApacheClient { 29 | public AndroidApacheClient() { 30 | super(AndroidHttpClient.newInstance("Retrofit")); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /retrofit/src/main/java/retrofit/mime/MimeUtil.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2013 Square, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package retrofit.mime; 17 | 18 | import java.util.regex.Matcher; 19 | import java.util.regex.Pattern; 20 | 21 | import static java.util.regex.Pattern.CASE_INSENSITIVE; 22 | 23 | public final class MimeUtil { 24 | private static final Pattern CHARSET = Pattern.compile("\\Wcharset=([^\\s;]+)", CASE_INSENSITIVE); 25 | 26 | /** Parse the MIME type from a {@code Content-Type} header value. */ 27 | public static String parseCharset(String mimeType) { 28 | Matcher match = CHARSET.matcher(mimeType); 29 | if (match.find()) { 30 | return match.group(1).replaceAll("[\"\\\\]", ""); 31 | } 32 | return "UTF-8"; 33 | } 34 | 35 | private MimeUtil() { 36 | // No instances. 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /retrofit/src/test/java/retrofit/mime/MimeUtilTest.java: -------------------------------------------------------------------------------- 1 | // Copyright 2012 Square, Inc. 2 | package retrofit.mime; 3 | 4 | import org.junit.Test; 5 | 6 | import static org.assertj.core.api.Assertions.assertThat; 7 | import static retrofit.mime.MimeUtil.parseCharset; 8 | 9 | public class MimeUtilTest { 10 | @Test public void charsetParsing() { 11 | assertThat(parseCharset("text/plain;charset=utf-8")).isEqualToIgnoringCase("UTF-8"); 12 | assertThat(parseCharset("text/plain; charset=utf-8")).isEqualToIgnoringCase("UTF-8"); 13 | assertThat(parseCharset("text/plain; charset=utf-8")).isEqualToIgnoringCase("UTF-8"); 14 | assertThat(parseCharset("text/plain; \tcharset=utf-8")).isEqualToIgnoringCase("UTF-8"); 15 | assertThat(parseCharset("text/plain; \r\n\tcharset=utf-8")).isEqualToIgnoringCase("UTF-8"); 16 | assertThat(parseCharset("text/plain; CHARSET=utf-8")).isEqualToIgnoringCase("UTF-8"); 17 | assertThat(parseCharset("text/plain; charset=UTF-8")).isEqualToIgnoringCase("UTF-8"); 18 | assertThat(parseCharset("text/plain; charset=\"\\u\\tf-\\8\"")).isEqualToIgnoringCase("UTF-8"); 19 | assertThat(parseCharset("text/plain; charset=\"utf-8\"")).isEqualToIgnoringCase("UTF-8"); 20 | assertThat(parseCharset("text/plain;charset=utf-8;other=thing")).isEqualToIgnoringCase("UTF-8"); 21 | assertThat(parseCharset("text/plain; notthecharset=utf-16;")).isEqualToIgnoringCase("UTF-8"); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /retrofit/src/main/java/retrofit/http/Path.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2013 Square, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package retrofit.http; 17 | 18 | import java.lang.annotation.Documented; 19 | import java.lang.annotation.Retention; 20 | import java.lang.annotation.Target; 21 | 22 | import static java.lang.annotation.ElementType.PARAMETER; 23 | import static java.lang.annotation.RetentionPolicy.RUNTIME; 24 | 25 | /** 26 | * Named replacement in the URL path. Values are converted to string using 27 | * {@link String#valueOf(Object)}. Replaced values will be URL encoded. 28 | *

29 | *

30 |  * @GET("/image/{id}")
31 |  * void example(@Path("id") int id, ..);
32 |  * 
33 | *

34 | * Path parameters may not be {@code null}. 35 | */ 36 | @Documented 37 | @Retention(RUNTIME) 38 | @Target(PARAMETER) 39 | public @interface Path { 40 | String value(); 41 | } 42 | -------------------------------------------------------------------------------- /retrofit/src/main/java/retrofit/mime/TypedString.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2013 Square, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package retrofit.mime; 17 | 18 | import java.io.UnsupportedEncodingException; 19 | 20 | public class TypedString extends TypedByteArray { 21 | 22 | public TypedString(String string) { 23 | super("text/plain; charset=UTF-8", convertToBytes(string)); 24 | } 25 | 26 | private static byte[] convertToBytes(String string) { 27 | try { 28 | return string.getBytes("UTF-8"); 29 | } catch (UnsupportedEncodingException e) { 30 | throw new RuntimeException(e); 31 | } 32 | } 33 | 34 | @Override public String toString() { 35 | try { 36 | return "TypedString[" + new String(getBytes(), "UTF-8") + "]"; 37 | } catch (UnsupportedEncodingException e) { 38 | throw new AssertionError("Must be able to decode UTF-8"); 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /retrofit-converters/simplexml/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 4.0.0 5 | 6 | 7 | com.squareup.retrofit 8 | retrofit-converters 9 | 1.6.2-SNAPSHOT 10 | ../pom.xml 11 | 12 | 13 | converter-simplexml 14 | Converter: SimpleXML 15 | 16 | 17 | 18 | com.squareup.retrofit 19 | retrofit 20 | ${project.version} 21 | 22 | 23 | org.simpleframework 24 | simple-xml 25 | 26 | 27 | 28 | junit 29 | junit 30 | test 31 | 32 | 33 | org.assertj 34 | assertj-core 35 | test 36 | 37 | 38 | com.google.guava 39 | guava 40 | test 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /retrofit-converters/jackson/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 4.0.0 5 | 6 | 7 | com.squareup.retrofit 8 | retrofit-converters 9 | 1.6.2-SNAPSHOT 10 | ../pom.xml 11 | 12 | 13 | converter-jackson 14 | Converter: Jackson 15 | 16 | 17 | 18 | com.squareup.retrofit 19 | retrofit 20 | ${project.version} 21 | 22 | 23 | com.fasterxml.jackson.core 24 | jackson-databind 25 | 26 | 27 | 28 | junit 29 | junit 30 | test 31 | 32 | 33 | org.assertj 34 | assertj-core 35 | test 36 | 37 | 38 | com.google.guava 39 | guava 40 | test 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /retrofit-converters/protobuf/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 4.0.0 5 | 6 | 7 | com.squareup.retrofit 8 | retrofit-converters 9 | 1.6.2-SNAPSHOT 10 | ../pom.xml 11 | 12 | 13 | converter-protobuf 14 | Converter: Protocol Buffers 15 | 16 | 17 | 18 | com.squareup.retrofit 19 | retrofit 20 | ${project.version} 21 | 22 | 23 | com.google.protobuf 24 | protobuf-java 25 | 26 | 27 | 28 | junit 29 | junit 30 | test 31 | 32 | 33 | org.assertj 34 | assertj-core 35 | test 36 | 37 | 38 | com.google.guava 39 | guava 40 | test 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /retrofit/src/main/java/retrofit/http/EncodedQueryMap.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2014 Square, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package retrofit.http; 17 | 18 | import java.lang.annotation.Documented; 19 | import java.lang.annotation.Retention; 20 | import java.lang.annotation.Target; 21 | 22 | import static java.lang.annotation.ElementType.PARAMETER; 23 | import static java.lang.annotation.RetentionPolicy.RUNTIME; 24 | 25 | /** 26 | * Query keys and values appended to the URL. 27 | *

28 | * Both keys and values are converted to strings using {@link String#valueOf(Object)}. Values are 29 | * not URL encoded. {@code null} values will not include the query parameter in the URL. See 30 | * {@link QueryMap @QueryMap} for URL-encoding equivalent. 31 | * 32 | * @see Query 33 | * @see QueryMap 34 | * @see EncodedQuery 35 | */ 36 | @Documented 37 | @Target(PARAMETER) 38 | @Retention(RUNTIME) 39 | public @interface EncodedQueryMap { 40 | } 41 | -------------------------------------------------------------------------------- /retrofit/src/main/java/retrofit/http/EncodedQuery.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2013 Square, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package retrofit.http; 17 | 18 | import java.lang.annotation.Documented; 19 | import java.lang.annotation.Retention; 20 | import java.lang.annotation.Target; 21 | 22 | import static java.lang.annotation.ElementType.PARAMETER; 23 | import static java.lang.annotation.RetentionPolicy.RUNTIME; 24 | 25 | /** 26 | * Encoded query parameter appended to the URL. 27 | *

28 | * Values are converted to strings using {@link String#valueOf(Object)}. Values are not URL 29 | * encoded. {@code null} values will not include the query parameter in the URL. See 30 | * {@link Query @Query} for URL-encoding equivalent. 31 | * 32 | * @see Query 33 | * @see QueryMap 34 | * @see EncodedQueryMap 35 | */ 36 | @Documented 37 | @Target(PARAMETER) 38 | @Retention(RUNTIME) 39 | public @interface EncodedQuery { 40 | String value(); 41 | } 42 | -------------------------------------------------------------------------------- /retrofit-converters/protobuf-nano/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 4.0.0 5 | 6 | 7 | com.squareup.retrofit 8 | retrofit-converters 9 | 1.6.2-SNAPSHOT 10 | ../pom.xml 11 | 12 | 13 | converter-protobuf-nano 14 | Converter: Nano Protocol Buffers 15 | 16 | 17 | 18 | com.squareup.retrofit 19 | retrofit 20 | ${project.version} 21 | 22 | 23 | com.google.protobuf 24 | protobuf-java 25 | 2.3.0 26 | 27 | 28 | com.google.guava 29 | guava 30 | 31 | 32 | 33 | junit 34 | junit 35 | test 36 | 37 | 38 | org.assertj 39 | assertj-core 40 | test 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /retrofit/src/main/java/retrofit/http/FormUrlEncoded.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2013 Square, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package retrofit.http; 17 | 18 | import java.lang.annotation.Documented; 19 | import java.lang.annotation.Retention; 20 | import java.lang.annotation.Target; 21 | 22 | import static java.lang.annotation.ElementType.METHOD; 23 | import static java.lang.annotation.RetentionPolicy.RUNTIME; 24 | 25 | /** 26 | * Denotes that the request body will use form URL encoding. Fields should be declared as 27 | * parameters and annotated with {@link Field @Field}. 28 | *

29 | * Requests made with this annotation will have {@code application/x-www-form-urlencoded} MIME 30 | * type. Field names and values will be UTF-8 encoded before being URI-encoded in accordance to 31 | * RFC-3986. 32 | */ 33 | @Documented 34 | @Target(METHOD) 35 | @Retention(RUNTIME) 36 | public @interface FormUrlEncoded { 37 | } 38 | -------------------------------------------------------------------------------- /retrofit/src/main/java/retrofit/http/EncodedPath.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2013 Square, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package retrofit.http; 17 | 18 | import java.lang.annotation.Documented; 19 | import java.lang.annotation.Retention; 20 | import java.lang.annotation.Target; 21 | 22 | import static java.lang.annotation.ElementType.PARAMETER; 23 | import static java.lang.annotation.RetentionPolicy.RUNTIME; 24 | 25 | /** 26 | * Named replacement in the URL path. Values are converted to string using 27 | * {@link String#valueOf(Object)}. Values are used literally without URL encoding. See 28 | * {@link retrofit.http.Path @Path} for URL encoding equivalent. 29 | *

30 | *

31 |  * @GET("/image/{id}")
32 |  * void example(@EncodedPath("id") int id, ..);
33 |  * 
34 | *

35 | * Path parameters may not be {@code null}. 36 | */ 37 | @Documented 38 | @Retention(RUNTIME) 39 | @Target(PARAMETER) 40 | public @interface EncodedPath { 41 | String value(); 42 | } 43 | -------------------------------------------------------------------------------- /retrofit-converters/wire/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | 4.0.0 9 | 10 | 11 | com.squareup.retrofit 12 | retrofit-converters 13 | 1.6.2-SNAPSHOT 14 | ../pom.xml 15 | 16 | 17 | converter-wire 18 | Converter: Wire Protocol Buffers 19 | 20 | 21 | 22 | com.squareup.retrofit 23 | retrofit 24 | ${project.version} 25 | 26 | 27 | com.squareup.wire 28 | wire-runtime 29 | 30 | 31 | 32 | junit 33 | junit 34 | test 35 | 36 | 37 | org.assertj 38 | assertj-core 39 | test 40 | 41 | 42 | com.google.guava 43 | guava 44 | test 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /retrofit/src/main/java/retrofit/http/Header.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2013 Square, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package retrofit.http; 17 | 18 | import java.lang.annotation.Documented; 19 | import java.lang.annotation.Retention; 20 | import java.lang.annotation.Target; 21 | 22 | import static java.lang.annotation.ElementType.PARAMETER; 23 | import static java.lang.annotation.RetentionPolicy.RUNTIME; 24 | 25 | /** 26 | * Replaces the header with the the value of its target. 27 | *

28 | *

29 |  * @GET("/")
30 |  * void foo(@Header("Accept-Language") String lang, Callback<Response> cb);
31 |  * 
32 | *

33 | * Header parameters may be {@code null} which will omit them from the request. 34 | *

35 | * Note: Headers do not overwrite each other. All headers with the same name will 36 | * be included in the request. 37 | * 38 | * @author Adrian Cole (adrianc@netflix.com) 39 | */ 40 | @Documented 41 | @Retention(RUNTIME) 42 | @Target(PARAMETER) 43 | public @interface Header { 44 | String value(); 45 | } 46 | -------------------------------------------------------------------------------- /retrofit/src/main/java/retrofit/http/Headers.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2013 Square, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package retrofit.http; 17 | 18 | import java.lang.annotation.Documented; 19 | import java.lang.annotation.Retention; 20 | import java.lang.annotation.Target; 21 | 22 | import static java.lang.annotation.ElementType.METHOD; 23 | import static java.lang.annotation.RetentionPolicy.RUNTIME; 24 | 25 | /** 26 | * Adds headers literally supplied in the {@code value}. 27 | *

28 | *

29 |  * @Headers("Cache-Control: max-age=640000")
30 |  * @GET("/")
31 |  * ...
32 |  *
33 |  * @Headers({
34 |  *   "X-Foo: Bar",
35 |  *   "X-Ping: Pong"
36 |  * })
37 |  * @GET("/")
38 |  * ...
39 |  * 
40 | *

41 | * Note: Headers do not overwrite each other. All headers with the same name will 42 | * be included in the request. 43 | * 44 | * @author Adrian Cole (adrianc@netflix.com) 45 | */ 46 | @Documented 47 | @Target(METHOD) 48 | @Retention(RUNTIME) 49 | public @interface Headers { 50 | String[] value(); 51 | } 52 | -------------------------------------------------------------------------------- /retrofit/src/main/java/retrofit/http/FieldMap.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2014 Square, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package retrofit.http; 17 | 18 | import java.lang.annotation.Documented; 19 | import java.lang.annotation.Retention; 20 | import java.lang.annotation.Target; 21 | 22 | import static java.lang.annotation.ElementType.PARAMETER; 23 | import static java.lang.annotation.RetentionPolicy.RUNTIME; 24 | 25 | /** 26 | * Named key/value pairs for a form-encoded request. 27 | *

28 | * Field values may be {@code null} which will omit them from the request body. 29 | *

30 | * Simple Example: 31 | *

32 |  * @FormUrlEncoded
33 |  * @POST("/things")
34 |  * void things(@FieldMap Map<String, String> fields);
35 |  * }
36 |  * 
37 | * Calling with {@code foo.things(ImmutableMap.of("foo", "bar", "kit", "kat")} yields a request 38 | * body of {@code foo=bar&kit=kat}. 39 | * 40 | * @see FormUrlEncoded 41 | * @see Field 42 | */ 43 | @Documented 44 | @Target(PARAMETER) 45 | @Retention(RUNTIME) 46 | public @interface FieldMap { 47 | } 48 | -------------------------------------------------------------------------------- /retrofit/src/main/java/retrofit/RequestInterceptor.java: -------------------------------------------------------------------------------- 1 | package retrofit; 2 | 3 | /** Intercept every request before it is executed in order to add additional data. */ 4 | public interface RequestInterceptor { 5 | /** Called for every request. Add data using methods on the supplied {@link RequestFacade}. */ 6 | void intercept(RequestFacade request); 7 | 8 | interface RequestFacade { 9 | /** Add a header to the request. This will not replace any existing headers. */ 10 | void addHeader(String name, String value); 11 | 12 | /** 13 | * Add a path parameter replacement. This works exactly like a {@link retrofit.http.Path 14 | * @Path}-annotated method argument. 15 | */ 16 | void addPathParam(String name, String value); 17 | 18 | /** 19 | * Add a path parameter replacement without first URI encoding. This works exactly like a 20 | * {@link retrofit.http.EncodedPath @EncodedPath}-annotated method argument. 21 | */ 22 | void addEncodedPathParam(String name, String value); 23 | 24 | /** Add an additional query parameter. This will not replace any existing query parameters. */ 25 | void addQueryParam(String name, String value); 26 | 27 | /** 28 | * Add an additional query parameter without first URI encoding. This will not replace any 29 | * existing query parameters. 30 | */ 31 | void addEncodedQueryParam(String name, String value); 32 | } 33 | 34 | /** A {@link RequestInterceptor} which does no modification of requests. */ 35 | RequestInterceptor NONE = new RequestInterceptor() { 36 | @Override public void intercept(RequestFacade request) { 37 | // Do nothing. 38 | } 39 | }; 40 | } 41 | -------------------------------------------------------------------------------- /retrofit/src/main/java/retrofit/Callback.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2012 Square, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package retrofit; 17 | 18 | import retrofit.client.Response; 19 | 20 | /** 21 | * Communicates responses from a server or offline requests. One and only one method will be 22 | * invoked in response to a given request. 23 | *

24 | * Callback methods are executed using the {@link RestAdapter} callback executor. When none is 25 | * specified, the following defaults are used: 26 | *

    27 | *
  • Android: Callbacks are executed on the application's main (UI) thread.
  • 28 | *
  • JVM: Callbacks are executed on the background thread which performed the request.
  • 29 | *
30 | * 31 | * @param expected response type 32 | * @see RestAdapter.Builder#setExecutors 33 | */ 34 | public interface Callback { 35 | 36 | /** Successful HTTP response. */ 37 | void success(T t, Response response); 38 | 39 | /** 40 | * Unsuccessful HTTP response due to network failure, non-2XX status code, or unexpected 41 | * exception. 42 | */ 43 | void failure(RetrofitError error); 44 | } 45 | -------------------------------------------------------------------------------- /website/static/jquery-maven-artifact.min.js: -------------------------------------------------------------------------------- 1 | /** 2 | * jQuery Maven Artifact Plugin 3 | * 4 | * Version: 1.0.1 5 | * Author: Jake Wharton 6 | * License: Apache 2.0 7 | */ 8 | (function($){function downloadUrl(groupId,artifactId,version,type){var groupPath=groupId.replace(/\./g,"/");return"http://repo1.maven.org/maven2/"+groupPath+"/"+artifactId+"/"+version+"/"+artifactId+"-"+version+type}$.fn.artifactVersion=function(groupId,artifactId,callback){if(typeof groupId!=="string"||typeof artifactId!=="string"){console.log("Error: groupId and artifactId are required.");return}if(typeof callback==="undefined"){console.log("Error: callback function required.");return}var url='http://search.maven.org/solrsearch/select/?q=g:"'+groupId+'"+AND+a:"'+artifactId+'"&wt=json&json.wrf=?';$.getJSON(url,function(response){var versions=response.response.docs;if(versions.length==0){return}var version=versions[0].latestVersion;var versionUrl=downloadUrl(groupId,artifactId,version,".jar");callback(version,versionUrl)})};$.fn.artifactVersions=function(groupId,artifactId,callback){if(typeof groupId!=="string"||typeof artifactId!=="string"){console.log("Error: groupId and artifactId are required.");return}if(typeof callback==="undefined"){console.log("Error: callback function required.");return}var url='http://search.maven.org/solrsearch/select/?q=g:"'+groupId+'"+AND+a:"'+artifactId+'"&wt=json&rows=10&core=gav&json.wrf=?';$.getJSON(url,function(response){var versions=response.response.docs;if(versions.length==0){return}versions.sort(function(o1,o2){return o1.v>o2.v?-1:1});var newVersions=[];for(var i=0;i 28 | * Both keys and values are converted to strings using {@link String#valueOf(Object)}. Values are 29 | * URL encoded and {@code null} will not include the query parameter in the URL. 30 | *

31 | * Simple Example: 32 | *

33 |  * @GET("/search")
34 |  * void list(@QueryMap Map<String, String> filters);
35 |  * 
36 | * Calling with {@code foo.list(ImmutableMap.of("foo", "bar", "kit", "kat"))} yields 37 | * {@code /search?foo=bar&kit=kat}. 38 | * 39 | * @see Query 40 | * @see QueryMap 41 | * @see EncodedQueryMap 42 | */ 43 | @Documented 44 | @Target(PARAMETER) 45 | @Retention(RUNTIME) 46 | public @interface QueryMap { 47 | } 48 | -------------------------------------------------------------------------------- /retrofit/src/main/java/retrofit/client/OkClient.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2013 Square, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package retrofit.client; 17 | 18 | import com.squareup.okhttp.OkHttpClient; 19 | import com.squareup.okhttp.OkUrlFactory; 20 | import java.io.IOException; 21 | import java.net.HttpURLConnection; 22 | import java.net.URL; 23 | import java.util.concurrent.TimeUnit; 24 | 25 | /** Retrofit client that uses OkHttp for communication. */ 26 | public class OkClient extends UrlConnectionClient { 27 | private static OkHttpClient generateDefaultOkHttp() { 28 | OkHttpClient client = new OkHttpClient(); 29 | client.setConnectTimeout(Defaults.CONNECT_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS); 30 | client.setReadTimeout(Defaults.READ_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS); 31 | return client; 32 | } 33 | 34 | private final OkUrlFactory okUrlFactory; 35 | 36 | public OkClient() { 37 | this(generateDefaultOkHttp()); 38 | } 39 | 40 | public OkClient(OkHttpClient client) { 41 | this.okUrlFactory = new OkUrlFactory(client); 42 | } 43 | 44 | @Override protected HttpURLConnection openConnection(Request request) throws IOException { 45 | return okUrlFactory.open(new URL(request.getUrl())); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /retrofit/src/test/java/retrofit/mime/TypedFileTest.java: -------------------------------------------------------------------------------- 1 | // Copyright 2010 Square, Inc. 2 | package retrofit.mime; 3 | 4 | import java.io.File; 5 | import java.io.FileOutputStream; 6 | import java.io.IOException; 7 | import org.junit.Test; 8 | 9 | import static org.assertj.core.api.Assertions.assertThat; 10 | 11 | public class TypedFileTest { 12 | private static final String PNG = "image/png"; 13 | 14 | @Test public void objectEquals() { 15 | TypedFile a1 = new TypedFile(PNG, new File("a.png")); 16 | TypedFile a2 = new TypedFile(PNG, new File("a.png")); 17 | TypedFile b = new TypedFile(PNG, new File("b.png")); 18 | 19 | assertThat(a1).isNotEqualTo(b); 20 | assertThat(a1.hashCode()).isNotEqualTo(b.hashCode()); 21 | assertThat(a1).isEqualTo(a2); 22 | assertThat(a1.hashCode()).isEqualTo(a2.hashCode()); 23 | } 24 | 25 | @Test public void objectToString() { 26 | File file = new File("/path/to/file.png"); 27 | 28 | assertThat(new TypedFile(PNG, file).toString()) // 29 | .isEqualTo(file.getAbsolutePath() + " (image/png)"); 30 | } 31 | 32 | @Test public void length() throws IOException { 33 | File tempFile = File.createTempFile("foo", ".tmp"); 34 | try { 35 | TypedFile typedFile = new TypedFile(PNG, tempFile); 36 | assertThat(typedFile.length()).isZero(); 37 | 38 | writeToFile(tempFile, new byte[] { 0, 1, 2, 3, 4 }); 39 | 40 | assertThat(tempFile.length()).isEqualTo(5); 41 | assertThat(typedFile.length()).isEqualTo(5); 42 | } finally { 43 | tempFile.delete(); 44 | } 45 | } 46 | 47 | private static void writeToFile(File file, byte[] data) throws IOException { 48 | FileOutputStream fos = new FileOutputStream(file); 49 | try { 50 | fos.write(data); 51 | } finally { 52 | fos.close(); 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /retrofit/src/main/java/retrofit/client/Client.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2013 Square, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package retrofit.client; 17 | 18 | import java.io.IOException; 19 | 20 | /** 21 | * Abstraction of an HTTP client which can execute {@link Request Requests}. This class must be 22 | * thread-safe as invocation may happen from multiple threads simultaneously. 23 | */ 24 | public interface Client { 25 | /** 26 | * Synchronously execute an HTTP represented by {@code request} and encapsulate all response data 27 | * into a {@link Response} instance. 28 | *

29 | * Note: If the request has a body, its length and mime type will have already been added to the 30 | * header list as {@code Content-Length} and {@code Content-Type}, respectively. Do NOT alter 31 | * these values as they might have been set as a result of an application-level configuration. 32 | */ 33 | Response execute(Request request) throws IOException; 34 | 35 | /** 36 | * Deferred means of obtaining a {@link Client}. For asynchronous requests this will always be 37 | * called on a background thread. 38 | */ 39 | interface Provider { 40 | /** Obtain an HTTP client. Called once for each request. */ 41 | Client get(); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /retrofit-mock/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 4.0.0 5 | 6 | 7 | com.squareup.retrofit 8 | parent 9 | 1.6.2-SNAPSHOT 10 | ../pom.xml 11 | 12 | 13 | retrofit-mock 14 | Retrofit Mock Adapter 15 | 16 | 17 | 18 | com.squareup.retrofit 19 | retrofit 20 | ${project.version} 21 | 22 | 23 | 24 | com.google.android 25 | android 26 | true 27 | 28 | 29 | 30 | com.netflix.rxjava 31 | rxjava-core 32 | true 33 | 34 | 35 | 36 | junit 37 | junit 38 | test 39 | 40 | 41 | org.assertj 42 | assertj-core 43 | test 44 | 45 | 46 | org.mockito 47 | mockito-core 48 | test 49 | 50 | 51 | com.google.guava 52 | guava 53 | test 54 | 55 | 56 | 57 | -------------------------------------------------------------------------------- /retrofit/src/test/java/retrofit/CallbackRunnableTest.java: -------------------------------------------------------------------------------- 1 | // Copyright 2013 Square, Inc. 2 | package retrofit; 3 | 4 | import java.util.concurrent.Executor; 5 | import org.junit.Before; 6 | import org.junit.Test; 7 | 8 | import static org.mockito.Matchers.any; 9 | import static org.mockito.Matchers.same; 10 | import static org.mockito.Mockito.mock; 11 | import static org.mockito.Mockito.spy; 12 | import static org.mockito.Mockito.verify; 13 | import static org.mockito.Mockito.when; 14 | import static retrofit.Utils.SynchronousExecutor; 15 | 16 | public class CallbackRunnableTest { 17 | private Executor executor = spy(new SynchronousExecutor()); 18 | private CallbackRunnable callbackRunnable; 19 | private Callback callback; 20 | private ErrorHandler errorHandler = ErrorHandler.DEFAULT; 21 | 22 | @Before public void setUp() { 23 | callback = mock(Callback.class); 24 | callbackRunnable = spy(new CallbackRunnable(callback, executor, errorHandler) { 25 | @Override public ResponseWrapper obtainResponse() { 26 | return null; // Must be mocked. 27 | } 28 | }); 29 | } 30 | 31 | @Test public void responsePassedToSuccess() { 32 | ResponseWrapper wrapper = new ResponseWrapper(null, new Object()); 33 | when(callbackRunnable.obtainResponse()).thenReturn(wrapper); 34 | 35 | callbackRunnable.run(); 36 | 37 | verify(executor).execute(any(Runnable.class)); 38 | verify(callback).success(same(wrapper.responseBody), same(wrapper.response)); 39 | } 40 | 41 | @Test public void errorPassedToFailure() { 42 | RetrofitError exception = RetrofitError.unexpectedError("", new RuntimeException()); 43 | when(callbackRunnable.obtainResponse()).thenThrow(exception); 44 | 45 | callbackRunnable.run(); 46 | 47 | verify(executor).execute(any(Runnable.class)); 48 | verify(callback).failure(same(exception)); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /retrofit/src/test/java/retrofit/mime/FormUrlEncodingTypedOutputTest.java: -------------------------------------------------------------------------------- 1 | // Copyright 2013 Square, Inc. 2 | package retrofit.mime; 3 | 4 | import java.io.ByteArrayOutputStream; 5 | import org.junit.Test; 6 | 7 | import static org.assertj.core.api.Assertions.assertThat; 8 | 9 | public class FormUrlEncodingTypedOutputTest { 10 | @Test public void urlEncoding() throws Exception { 11 | FormUrlEncodedTypedOutput fe = new FormUrlEncodedTypedOutput(); 12 | fe.addField("a&b", "c=d"); 13 | fe.addField("space, the", "final frontier"); 14 | 15 | ByteArrayOutputStream out = new ByteArrayOutputStream(); 16 | fe.writeTo(out); 17 | String actual = new String(out.toByteArray(), "UTF-8"); 18 | assertThat(actual).isEqualTo("a%26b=c%3Dd&space%2C+the=final+frontier"); 19 | } 20 | 21 | @Test public void utf8encoding() throws Exception { 22 | FormUrlEncodedTypedOutput fe = new FormUrlEncodedTypedOutput(); 23 | fe.addField("ooɟ", "ɹɐq"); 24 | 25 | ByteArrayOutputStream out = new ByteArrayOutputStream(); 26 | fe.writeTo(out); 27 | String actual = new String(out.toByteArray(), "UTF-8"); 28 | assertThat(actual).isEqualTo("oo%C9%9F=%C9%B9%C9%90q"); 29 | } 30 | 31 | @Test public void encodedPairs() throws Exception { 32 | FormUrlEncodedTypedOutput fe = new FormUrlEncodedTypedOutput(); 33 | fe.addField("sim", "ple"); 34 | 35 | ByteArrayOutputStream out1 = new ByteArrayOutputStream(); 36 | fe.writeTo(out1); 37 | String actual1 = new String(out1.toByteArray(), "UTF-8"); 38 | assertThat(actual1).isEqualTo("sim=ple"); 39 | 40 | fe.addField("hey", "there"); 41 | fe.addField("help", "me"); 42 | 43 | ByteArrayOutputStream out2 = new ByteArrayOutputStream(); 44 | fe.writeTo(out2); 45 | String actual2 = new String(out2.toByteArray(), "UTF-8"); 46 | assertThat(actual2).isEqualTo("sim=ple&hey=there&help=me"); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /retrofit/src/main/java/retrofit/http/Body.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2011 Square, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package retrofit.http; 17 | 18 | import java.lang.annotation.Documented; 19 | import java.lang.annotation.Retention; 20 | import java.lang.annotation.Target; 21 | 22 | import static java.lang.annotation.ElementType.PARAMETER; 23 | import static java.lang.annotation.RetentionPolicy.RUNTIME; 24 | 25 | /** 26 | * Use this annotation on a service method param when you want to directly control the request body 27 | * of a POST/PUT request (instead of sending in as request parameters or form-style request 28 | * body). If the value of the parameter implements {@link retrofit.mime.TypedOutput TypedOutput}, 29 | * the request body will be written exactly as specified by 30 | * {@link retrofit.mime.TypedOutput#writeTo(java.io.OutputStream)}. If the value does not implement 31 | * TypedOutput, the object will be serialized using the {@link retrofit.RestAdapter RestAdapter}'s 32 | * {@link retrofit.converter.Converter Converter} and the result will be set directly as the 33 | * request body. 34 | *

35 | * Body parameters may not be {@code null}. 36 | * 37 | * @author Eric Denman (edenman@squareup.com) 38 | */ 39 | @Documented 40 | @Target(PARAMETER) 41 | @Retention(RUNTIME) 42 | public @interface Body { 43 | } 44 | -------------------------------------------------------------------------------- /retrofit/src/main/java/retrofit/client/Header.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2012 Square, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package retrofit.client; 17 | 18 | /** Represents an HTTP header name/value pair. */ 19 | public final class Header { 20 | private final String name; 21 | private final String value; 22 | 23 | public Header(String name, String value) { 24 | this.name = name; 25 | this.value = value; 26 | } 27 | 28 | public String getName() { 29 | return name; 30 | } 31 | 32 | public String getValue() { 33 | return value; 34 | } 35 | 36 | @Override public boolean equals(Object o) { 37 | if (this == o) return true; 38 | if (o == null || getClass() != o.getClass()) return false; 39 | 40 | Header header = (Header) o; 41 | 42 | if (name != null ? !name.equals(header.name) : header.name != null) return false; 43 | if (value != null ? !value.equals(header.value) : header.value != null) return false; 44 | 45 | return true; 46 | } 47 | 48 | @Override public int hashCode() { 49 | int result = name != null ? name.hashCode() : 0; 50 | result = 31 * result + (value != null ? value.hashCode() : 0); 51 | return result; 52 | } 53 | 54 | @Override public String toString() { 55 | return (name != null ? name : "") + ": " + (value != null ? value : ""); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /retrofit/src/main/java/retrofit/http/PartMap.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2014 Square, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package retrofit.http; 17 | 18 | import java.lang.annotation.Documented; 19 | import java.lang.annotation.Retention; 20 | import java.lang.annotation.Target; 21 | 22 | import static java.lang.annotation.ElementType.PARAMETER; 23 | import static java.lang.annotation.RetentionPolicy.RUNTIME; 24 | 25 | /** 26 | * Denotes name and value parts of a multi-part request 27 | *

28 | * Values of the map on which this annotation exists will be processed in one of three ways: 29 | *

    30 | *
  • If the type implements {@link retrofit.mime.TypedOutput TypedOutput} the headers and 31 | * body will be used directly.
  • 32 | *
  • If the type is {@link String} the value will also be used directly with a {@code text/plain} 33 | * content type.
  • 34 | *
  • Other object types will be converted to an appropriate representation by calling {@link 35 | * retrofit.converter.Converter#toBody(Object)}.
  • 36 | *
37 | *

38 | *

39 |  * @Multipart
40 |  * @POST("/upload")
41 |  * void upload(@Part("file") TypedFile file, @PartMap Map<String, String> params);
42 |  * 
43 | *

44 | * 45 | * @see Multipart 46 | * @see Part 47 | */ 48 | @Documented 49 | @Target(PARAMETER) 50 | @Retention(RUNTIME) 51 | public @interface PartMap { 52 | } 53 | -------------------------------------------------------------------------------- /retrofit-samples/github-client/src/main/java/com/example/retrofit/GitHubClient.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2012 Square, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.example.retrofit; 17 | 18 | import java.util.List; 19 | import retrofit.RestAdapter; 20 | import retrofit.http.GET; 21 | import retrofit.http.Path; 22 | 23 | public class GitHubClient { 24 | private static final String API_URL = "https://api.github.com"; 25 | 26 | static class Contributor { 27 | String login; 28 | int contributions; 29 | } 30 | 31 | interface GitHub { 32 | @GET("/repos/{owner}/{repo}/contributors") 33 | List contributors( 34 | @Path("owner") String owner, 35 | @Path("repo") String repo 36 | ); 37 | } 38 | 39 | public static void main(String... args) { 40 | // Create a very simple REST adapter which points the GitHub API endpoint. 41 | RestAdapter restAdapter = new RestAdapter.Builder() 42 | .setEndpoint(API_URL) 43 | .build(); 44 | 45 | // Create an instance of our GitHub API interface. 46 | GitHub github = restAdapter.create(GitHub.class); 47 | 48 | // Fetch and print a list of the contributors to this library. 49 | List contributors = github.contributors("square", "retrofit"); 50 | for (Contributor contributor : contributors) { 51 | System.out.println(contributor.login + " (" + contributor.contributions + ")"); 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /retrofit-converters/simplexml/src/main/java/retrofit/converter/SimpleXMLConverter.java: -------------------------------------------------------------------------------- 1 | package retrofit.converter; 2 | 3 | import java.io.ByteArrayOutputStream; 4 | import java.io.IOException; 5 | import java.io.OutputStreamWriter; 6 | import java.lang.reflect.Type; 7 | 8 | import org.simpleframework.xml.core.Persister; 9 | import org.simpleframework.xml.Serializer; 10 | 11 | import retrofit.mime.TypedByteArray; 12 | import retrofit.mime.TypedInput; 13 | import retrofit.mime.TypedOutput; 14 | 15 | /** 16 | * A {@link Converter} which uses SimpleXML for reading and writing entities. 17 | * 18 | * @author Fabien Ric (fabien.ric@gmail.com) 19 | */ 20 | public class SimpleXMLConverter implements Converter { 21 | private static final String CHARSET = "UTF-8"; 22 | private static final String MIME_TYPE = "application/xml; charset=" + CHARSET; 23 | 24 | private final Serializer serializer; 25 | 26 | public SimpleXMLConverter() { 27 | this(new Persister()); 28 | } 29 | 30 | public SimpleXMLConverter(Serializer serializer) { 31 | this.serializer = serializer; 32 | } 33 | 34 | @Override public Object fromBody(TypedInput body, Type type) throws ConversionException { 35 | try { 36 | return serializer.read((Class) type, body.in()); 37 | } catch (Exception e) { 38 | throw new ConversionException(e); 39 | } 40 | } 41 | 42 | @Override public TypedOutput toBody(Object source) { 43 | OutputStreamWriter osw = null; 44 | 45 | try { 46 | ByteArrayOutputStream bos = new ByteArrayOutputStream(); 47 | osw = new OutputStreamWriter(bos, CHARSET); 48 | serializer.write(source, osw); 49 | osw.flush(); 50 | return new TypedByteArray(MIME_TYPE, bos.toByteArray()); 51 | } catch (Exception e) { 52 | throw new AssertionError(e); 53 | } finally { 54 | try { 55 | if (osw != null) { 56 | osw.close(); 57 | } 58 | } catch (IOException e) { 59 | throw new AssertionError(e); 60 | } 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /retrofit/src/main/java/retrofit/converter/Converter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2012 Square, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package retrofit.converter; 17 | 18 | import java.lang.reflect.Type; 19 | import retrofit.mime.TypedInput; 20 | import retrofit.mime.TypedOutput; 21 | 22 | /** 23 | * Arbiter for converting objects to and from their representation in HTTP. 24 | * 25 | * @author Jake Wharton (jw@squareup.com) 26 | */ 27 | public interface Converter { 28 | /** 29 | * Convert an HTTP response body to a concrete object of the specified type. 30 | * 31 | * @param body HTTP response body. 32 | * @param type Target object type. 33 | * @return Instance of {@code type} which will be cast by the caller. 34 | * @throws ConversionException if conversion was unable to complete. This will trigger a call to 35 | * {@link retrofit.Callback#failure(retrofit.RetrofitError)} or throw a 36 | * {@link retrofit.RetrofitError}. The exception message should report all necessary information 37 | * about its cause as the response body will be set to {@code null}. 38 | */ 39 | Object fromBody(TypedInput body, Type type) throws ConversionException; 40 | 41 | /** 42 | * Convert an object to an appropriate representation for HTTP transport. 43 | * 44 | * @param object Object instance to convert. 45 | * @return Representation of the specified object as bytes. 46 | */ 47 | TypedOutput toBody(Object object); 48 | } 49 | -------------------------------------------------------------------------------- /retrofit-converters/jackson/src/main/java/retrofit/converter/JacksonConverter.java: -------------------------------------------------------------------------------- 1 | package retrofit.converter; 2 | 3 | import com.fasterxml.jackson.core.JsonParseException; 4 | import com.fasterxml.jackson.core.JsonProcessingException; 5 | import com.fasterxml.jackson.databind.JavaType; 6 | import com.fasterxml.jackson.databind.JsonMappingException; 7 | import com.fasterxml.jackson.databind.ObjectMapper; 8 | import java.io.IOException; 9 | import java.io.UnsupportedEncodingException; 10 | import java.lang.reflect.Type; 11 | import retrofit.mime.TypedByteArray; 12 | import retrofit.mime.TypedInput; 13 | import retrofit.mime.TypedOutput; 14 | 15 | /** 16 | * A {@link Converter} which uses Jackson for reading and writing entities. 17 | * 18 | * @author Kai Waldron (kaiwaldron@gmail.com) 19 | */ 20 | public class JacksonConverter implements Converter { 21 | private static final String MIME_TYPE = "application/json; charset=UTF-8"; 22 | 23 | private final ObjectMapper objectMapper; 24 | 25 | public JacksonConverter() { 26 | this(new ObjectMapper()); 27 | } 28 | 29 | public JacksonConverter(ObjectMapper objectMapper) { 30 | this.objectMapper = objectMapper; 31 | } 32 | 33 | @Override public Object fromBody(TypedInput body, Type type) throws ConversionException { 34 | try { 35 | JavaType javaType = objectMapper.getTypeFactory().constructType(type); 36 | return objectMapper.readValue(body.in(), javaType); 37 | } catch (JsonParseException e) { 38 | throw new ConversionException(e); 39 | } catch (JsonMappingException e) { 40 | throw new ConversionException(e); 41 | } catch (IOException e) { 42 | throw new ConversionException(e); 43 | } 44 | } 45 | 46 | @Override public TypedOutput toBody(Object object) { 47 | try { 48 | String json = objectMapper.writeValueAsString(object); 49 | return new TypedByteArray(MIME_TYPE, json.getBytes("UTF-8")); 50 | } catch (JsonProcessingException e) { 51 | throw new AssertionError(e); 52 | } catch (UnsupportedEncodingException e) { 53 | throw new AssertionError(e); 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /retrofit/src/main/java/retrofit/http/Part.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2013 Square, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package retrofit.http; 17 | 18 | import java.lang.annotation.Documented; 19 | import java.lang.annotation.Retention; 20 | import java.lang.annotation.Target; 21 | 22 | import static java.lang.annotation.ElementType.PARAMETER; 23 | import static java.lang.annotation.RetentionPolicy.RUNTIME; 24 | 25 | /** 26 | * Denotes a single part of a multi-part request. 27 | *

28 | * The parameter type on which this annotation exists will be processed in one of three ways: 29 | *

    30 | *
  • If the type implements {@link retrofit.mime.TypedOutput TypedOutput} the headers and 31 | * body will be used directly.
  • 32 | *
  • If the type is {@link String} the value will also be used directly with a {@code text/plain} 33 | * content type.
  • 34 | *
  • Other object types will be converted to an appropriate representation by calling {@link 35 | * retrofit.converter.Converter#toBody(Object)}.
  • 36 | *
37 | *

38 | * Values may be {@code null} which will omit them from the request body. 39 | *

40 | *

41 |  * @Multipart
42 |  * @POST("/")
43 |  * void example(@Part("description") String description,
44 |  *              @Part("image") TypedFile image,
45 |  *              ...
46 |  * );
47 |  * 
48 | *

49 | * Part parameters may not be {@code null}. 50 | */ 51 | @Documented 52 | @Target(PARAMETER) 53 | @Retention(RUNTIME) 54 | public @interface Part { 55 | String value(); 56 | } 57 | -------------------------------------------------------------------------------- /retrofit/src/main/java/retrofit/mime/FormUrlEncodedTypedOutput.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2013 Square, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package retrofit.mime; 17 | 18 | import java.io.ByteArrayOutputStream; 19 | import java.io.IOException; 20 | import java.io.OutputStream; 21 | import java.net.URLEncoder; 22 | 23 | public final class FormUrlEncodedTypedOutput implements TypedOutput { 24 | final ByteArrayOutputStream content = new ByteArrayOutputStream(); 25 | 26 | public void addField(String name, String value) { 27 | if (name == null) { 28 | throw new NullPointerException("name"); 29 | } 30 | if (value == null) { 31 | throw new NullPointerException("value"); 32 | } 33 | if (content.size() > 0) { 34 | content.write('&'); 35 | } 36 | try { 37 | name = URLEncoder.encode(name, "UTF-8"); 38 | value = URLEncoder.encode(value, "UTF-8"); 39 | 40 | content.write(name.getBytes("UTF-8")); 41 | content.write('='); 42 | content.write(value.getBytes("UTF-8")); 43 | } catch (IOException e) { 44 | throw new RuntimeException(e); 45 | } 46 | } 47 | 48 | @Override public String fileName() { 49 | return null; 50 | } 51 | 52 | @Override public String mimeType() { 53 | return "application/x-www-form-urlencoded; charset=UTF-8"; 54 | } 55 | 56 | @Override public long length() { 57 | return content.size(); 58 | } 59 | 60 | @Override public void writeTo(OutputStream out) throws IOException { 61 | out.write(content.toByteArray()); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /retrofit/src/main/java/retrofit/http/Field.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2013 Square, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package retrofit.http; 17 | 18 | import java.lang.annotation.Documented; 19 | import java.lang.annotation.Retention; 20 | import java.lang.annotation.Target; 21 | 22 | import static java.lang.annotation.ElementType.PARAMETER; 23 | import static java.lang.annotation.RetentionPolicy.RUNTIME; 24 | 25 | /** 26 | * Named pair for a form-encoded request. 27 | *

28 | * Values are converted to strings using {@link String#valueOf(Object)} and then form URL encoded. 29 | * {@code null} values are ignored. Passing a {@link java.util.List List} or array will result in a 30 | * field pair for each non-{@code null} item. 31 | *

32 | * Simple Example: 33 | *

34 |  * @FormUrlEncoded
35 |  * @POST("/")
36 |  * void example(@Field("name") String name, @Field("occupation") String occupation);
37 |  * }
38 |  * 
39 | * Calling with {@code foo.example("Bob Smith", "President")} yields a request body of 40 | * {@code name=Bob+Smith&occupation=President}. 41 | *

42 | * Array Example: 43 | *

44 |  * @FormUrlEncoded
45 |  * @POST("/list")
46 |  * void example(@Field("name") String... names);
47 |  * 
48 | * Calling with {@code foo.example("Bob Smith", "Jane Doe")} yields a request body of 49 | * {@code name=Bob+Smith&name=Jane+Doe}. 50 | * 51 | * @see FormUrlEncoded 52 | * @see FieldMap 53 | */ 54 | @Documented 55 | @Target(PARAMETER) 56 | @Retention(RUNTIME) 57 | public @interface Field { 58 | String value(); 59 | } 60 | -------------------------------------------------------------------------------- /retrofit-mock/src/main/java/retrofit/android/AndroidMockValuePersistence.java: -------------------------------------------------------------------------------- 1 | // Copyright 2013 Square, Inc. 2 | package retrofit.android; 3 | 4 | import android.content.SharedPreferences; 5 | import retrofit.MockRestAdapter; 6 | 7 | /** 8 | * A {@link MockRestAdapter.ValueChangeListener value change listener} for {@link MockRestAdapter} 9 | * which stores any customized behavior values into shared preferences. 10 | */ 11 | public final class AndroidMockValuePersistence implements MockRestAdapter.ValueChangeListener { 12 | private static final String KEY_DELAY = "retrofit-mock-delay"; 13 | private static final String KEY_VARIANCE = "retrofit-mock-variance"; 14 | private static final String KEY_ERROR = "retrofit-mock-error"; 15 | 16 | /** 17 | * Install a {@link MockRestAdapter.ValueChangeListener value change listener} on the supplied 18 | * {@link MockRestAdapter} using the {@link SharedPreferences} for storing customized behavior 19 | * values. Invoking this will load any existing stored values for the mock adapter's behavior. 20 | */ 21 | public static void install(MockRestAdapter mockRestAdapter, SharedPreferences preferences) { 22 | long delay = preferences.getLong(KEY_DELAY, -1); 23 | if (delay != -1) { 24 | mockRestAdapter.setDelay(delay); 25 | } 26 | 27 | int variance = preferences.getInt(KEY_VARIANCE, -1); 28 | if (variance != -1) { 29 | mockRestAdapter.setVariancePercentage(variance); 30 | } 31 | 32 | int error = preferences.getInt(KEY_ERROR, -1); 33 | if (error != -1) { 34 | mockRestAdapter.setErrorPercentage(error); 35 | } 36 | 37 | mockRestAdapter.setValueChangeListener(new AndroidMockValuePersistence(preferences)); 38 | } 39 | 40 | private final SharedPreferences preferences; 41 | 42 | private AndroidMockValuePersistence(SharedPreferences preferences) { 43 | this.preferences = preferences; 44 | } 45 | 46 | @Override public void onMockValuesChanged(long delayMs, int variancePct, int errorPct) { 47 | preferences.edit() 48 | .putLong(KEY_DELAY, delayMs) 49 | .putInt(KEY_VARIANCE, variancePct) 50 | .putInt(KEY_ERROR, errorPct) 51 | .apply(); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /retrofit/src/main/java/retrofit/http/Query.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2013 Square, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package retrofit.http; 17 | 18 | import java.lang.annotation.Documented; 19 | import java.lang.annotation.Retention; 20 | import java.lang.annotation.Target; 21 | 22 | import static java.lang.annotation.ElementType.PARAMETER; 23 | import static java.lang.annotation.RetentionPolicy.RUNTIME; 24 | 25 | /** 26 | * Query parameter appended to the URL. 27 | *

28 | * Values are converted to strings using {@link String#valueOf(Object)} and then URL encoded. 29 | * {@code null} values are ignored. Passing a {@link java.util.List List} or array will result in a 30 | * query parameter for each non-{@code null} item. 31 | *

32 | * Simple Example: 33 | *

34 |  * @GET("/list")
35 |  * void list(@Query("page") int page);
36 |  * 
37 | * Calling with {@code foo.list(1)} yields {@code /list?page=1}. 38 | *

39 | * Example with {@code null}: 40 | *

41 |  * @GET("/list")
42 |  * void list(@Query("category") String category);
43 |  * 
44 | * Calling with {@code foo.list(null)} yields {@code /list}. 45 | *

46 | * Array Example: 47 | *

48 |  * @GET("/list")
49 |  * void list(@Query("category") String... categories);
50 |  * 
51 | * Calling with {@code foo.list("bar", "baz")} yields 52 | * {@code /list?category=foo&category=bar}. 53 | * 54 | * @see EncodedQuery 55 | * @see QueryMap 56 | * @see EncodedQueryMap 57 | */ 58 | @Documented 59 | @Target(PARAMETER) 60 | @Retention(RUNTIME) 61 | public @interface Query { 62 | String value(); 63 | } 64 | -------------------------------------------------------------------------------- /retrofit/src/main/java/retrofit/ErrorHandler.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2013 Square, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package retrofit; 17 | 18 | /** 19 | * A hook allowing clients to customize {@link retrofit.client.Response response} exceptions. 20 | * 21 | * @author Sam Beran sberan@gmail.com 22 | */ 23 | public interface ErrorHandler { 24 | /** 25 | * Return a custom exception to be thrown for a {@link RetrofitError}. It is recommended that you 26 | * pass the supplied error as the cause to any new exceptions. 27 | *

28 | * If the return exception is checked it must be declared to be thrown on the interface method. 29 | *

30 | * Example usage: 31 | *

32 |    * class MyErrorHandler implements ErrorHandler {
33 |    *   @Override public Throwable handleError(RetrofitError cause) {
34 |    *     Response r = cause.getResponse();
35 |    *     if (r != null && r.getStatus() == 401) {
36 |    *       return new UnauthorizedException(cause);
37 |    *     }
38 |    *     return cause;
39 |    *   }
40 |    * }
41 |    * 
42 | * 43 | * @param cause the original {@link RetrofitError} exception 44 | * @return Throwable an exception which will be thrown from a synchronous interface method or 45 | * passed to an asynchronous error callback. Must not be {@code null}. 46 | */ 47 | Throwable handleError(RetrofitError cause); 48 | 49 | /** An {@link ErrorHandler} which returns the original error. */ 50 | ErrorHandler DEFAULT = new ErrorHandler() { 51 | @Override public Throwable handleError(RetrofitError cause) { 52 | return cause; 53 | } 54 | }; 55 | } 56 | -------------------------------------------------------------------------------- /retrofit/src/main/java/retrofit/client/Request.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2013 Square, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package retrofit.client; 17 | 18 | import java.util.ArrayList; 19 | import java.util.Collections; 20 | import java.util.List; 21 | import retrofit.mime.TypedOutput; 22 | 23 | /** Encapsulates all of the information necessary to make an HTTP request. */ 24 | public final class Request { 25 | private final String method; 26 | private final String url; 27 | private final List
headers; 28 | private final TypedOutput body; 29 | 30 | public Request(String method, String url, List
headers, TypedOutput body) { 31 | if (method == null) { 32 | throw new NullPointerException("Method must not be null."); 33 | } 34 | if (url == null) { 35 | throw new NullPointerException("URL must not be null."); 36 | } 37 | this.method = method; 38 | this.url = url; 39 | 40 | if (headers == null) { 41 | this.headers = Collections.emptyList(); 42 | } else { 43 | this.headers = Collections.unmodifiableList(new ArrayList
(headers)); 44 | } 45 | 46 | this.body = body; 47 | } 48 | 49 | /** HTTP method verb. */ 50 | public String getMethod() { 51 | return method; 52 | } 53 | 54 | /** Target URL. */ 55 | public String getUrl() { 56 | return url; 57 | } 58 | 59 | /** Returns an unmodifiable list of headers, never {@code null}. */ 60 | public List
getHeaders() { 61 | return headers; 62 | } 63 | 64 | /** Returns the request body or {@code null}. */ 65 | public TypedOutput getBody() { 66 | return body; 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /website/static/html5shiv.min.js: -------------------------------------------------------------------------------- 1 | /* 2 | HTML5 Shiv v3.6.2pre | @afarkas @jdalton @jon_neal @rem | MIT/GPL2 Licensed 3 | */ 4 | (function(l,f){function m(){var a=e.elements;return"string"==typeof a?a.split(" "):a}function i(a){var b=n[a[o]];b||(b={},h++,a[o]=h,n[h]=b);return b}function p(a,b,c){b||(b=f);if(g)return b.createElement(a);c||(c=i(b));b=c.cache[a]?c.cache[a].cloneNode():r.test(a)?(c.cache[a]=c.createElem(a)).cloneNode():c.createElem(a);return b.canHaveChildren&&!s.test(a)?c.frag.appendChild(b):b}function t(a,b){if(!b.cache)b.cache={},b.createElem=a.createElement,b.createFrag=a.createDocumentFragment,b.frag=b.createFrag(); 5 | a.createElement=function(c){return!e.shivMethods?b.createElem(c):p(c,a,b)};a.createDocumentFragment=Function("h,f","return function(){var n=f.cloneNode(),c=n.createElement;h.shivMethods&&("+m().join().replace(/\w+/g,function(a){b.createElem(a);b.frag.createElement(a);return'c("'+a+'")'})+");return n}")(e,b.frag)}function q(a){a||(a=f);var b=i(a);if(e.shivCSS&&!j&&!b.hasCSS){var c,d=a;c=d.createElement("p");d=d.getElementsByTagName("head")[0]||d.documentElement;c.innerHTML="x"; 6 | c=d.insertBefore(c.lastChild,d.firstChild);b.hasCSS=!!c}g||t(a,b);return a}var k=l.html5||{},s=/^<|^(?:button|map|select|textarea|object|iframe|option|optgroup)$/i,r=/^(?:a|b|code|div|fieldset|h1|h2|h3|h4|h5|h6|i|label|li|ol|p|q|span|strong|style|table|tbody|td|th|tr|ul)$/i,j,o="_html5shiv",h=0,n={},g;(function(){try{var a=f.createElement("a");a.innerHTML="";j="hidden"in a;var b;if(!(b=1==a.childNodes.length)){f.createElement("a");var c=f.createDocumentFragment();b="undefined"==typeof c.cloneNode|| 7 | "undefined"==typeof c.createDocumentFragment||"undefined"==typeof c.createElement}g=b}catch(d){g=j=!0}})();var e={elements:k.elements||"abbr article aside audio bdi canvas data datalist details figcaption figure footer header hgroup mark meter nav output progress section summary time video",version:"3.6.2pre",shivCSS:!1!==k.shivCSS,supportsUnknownElements:g,shivMethods:!1!==k.shivMethods,type:"default",shivDocument:q,createElement:p,createDocumentFragment:function(a,b){a||(a=f);if(g)return a.createDocumentFragment(); 8 | for(var b=b||i(a),c=b.frag.cloneNode(),d=0,e=m(),h=e.length;d)) { 20 | throw new IllegalArgumentException("Expected a raw Class but was " + type); 21 | } 22 | Class c = (Class) type; 23 | if (!AbstractMessageLite.class.isAssignableFrom(c)) { 24 | throw new IllegalArgumentException("Expected a protobuf message but was " + c.getName()); 25 | } 26 | 27 | String mimeType = body.mimeType(); 28 | if (!MIME_TYPE.equals(mimeType)) { 29 | throw new ConversionException("Response content type was not a proto: " + mimeType); 30 | } 31 | 32 | try { 33 | Method parseFrom = c.getMethod("parseFrom", InputStream.class); 34 | return parseFrom.invoke(null, body.in()); 35 | } catch (InvocationTargetException e) { 36 | throw new ConversionException(c.getName() + ".parseFrom() failed", e.getCause()); 37 | } catch (NoSuchMethodException e) { 38 | throw new IllegalArgumentException("Expected a protobuf message but was " + c.getName()); 39 | } catch (IllegalAccessException e) { 40 | throw new AssertionError(); 41 | } catch (IOException e) { 42 | throw new ConversionException(e); 43 | } 44 | } 45 | 46 | @Override public TypedOutput toBody(Object object) { 47 | if (!(object instanceof AbstractMessageLite)) { 48 | throw new IllegalArgumentException( 49 | "Expected a protobuf message but was " + (object != null ? object.getClass().getName() 50 | : "null")); 51 | } 52 | byte[] bytes = ((AbstractMessageLite) object).toByteArray(); 53 | return new TypedByteArray(MIME_TYPE, bytes); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /retrofit/src/main/java/retrofit/CallbackRunnable.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2012 Square, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package retrofit; 17 | 18 | import java.util.concurrent.Executor; 19 | 20 | import static retrofit.RetrofitError.unexpectedError; 21 | 22 | /** 23 | * A {@link Runnable} executed on a background thread to invoke {@link #obtainResponse()} which 24 | * performs an HTTP request. The response of the request, whether it be an object or exception, is 25 | * then marshaled to the supplied {@link Executor} in the form of a method call on a 26 | * {@link Callback}. 27 | */ 28 | abstract class CallbackRunnable implements Runnable { 29 | private final Callback callback; 30 | private final Executor callbackExecutor; 31 | private final ErrorHandler errorHandler; 32 | 33 | CallbackRunnable(Callback callback, Executor callbackExecutor, ErrorHandler errorHandler) { 34 | this.callback = callback; 35 | this.callbackExecutor = callbackExecutor; 36 | this.errorHandler = errorHandler; 37 | } 38 | 39 | @SuppressWarnings("unchecked") 40 | @Override public final void run() { 41 | try { 42 | final ResponseWrapper wrapper = obtainResponse(); 43 | callbackExecutor.execute(new Runnable() { 44 | @Override public void run() { 45 | callback.success((T) wrapper.responseBody, wrapper.response); 46 | } 47 | }); 48 | } catch (RetrofitError e) { 49 | Throwable cause = errorHandler.handleError(e); 50 | final RetrofitError handled = cause == e ? e : unexpectedError(e.getUrl(), cause); 51 | callbackExecutor.execute(new Runnable() { 52 | @Override public void run() { 53 | callback.failure(handled); 54 | } 55 | }); 56 | } 57 | } 58 | 59 | public abstract ResponseWrapper obtainResponse(); 60 | } 61 | -------------------------------------------------------------------------------- /retrofit-converters/wire/src/main/java/retrofit/converter/WireConverter.java: -------------------------------------------------------------------------------- 1 | // Copyright 2013 Square, Inc. 2 | package retrofit.converter; 3 | 4 | import com.squareup.wire.Message; 5 | import com.squareup.wire.Wire; 6 | import java.io.IOException; 7 | import java.io.InputStream; 8 | import java.lang.reflect.Type; 9 | import retrofit.mime.TypedByteArray; 10 | import retrofit.mime.TypedInput; 11 | import retrofit.mime.TypedOutput; 12 | 13 | /** A {@link Converter} that reads and writes protocol buffers using Wire. */ 14 | public class WireConverter implements Converter { 15 | private static final String MIME_TYPE = "application/x-protobuf"; 16 | 17 | private final Wire wire; 18 | 19 | /** Create a converter with a default {@link Wire} instance. */ 20 | public WireConverter() { 21 | this(new Wire()); 22 | } 23 | 24 | /** Create a converter using the supplied {@link Wire} instance. */ 25 | public WireConverter(Wire wire) { 26 | this.wire = wire; 27 | } 28 | 29 | @SuppressWarnings("unchecked") // 30 | @Override public Object fromBody(TypedInput body, Type type) throws ConversionException { 31 | if (!(type instanceof Class)) { 32 | throw new IllegalArgumentException("Expected a raw Class but was " + type); 33 | } 34 | Class c = (Class) type; 35 | if (!Message.class.isAssignableFrom(c)) { 36 | throw new IllegalArgumentException("Expected a proto message but was " + c.getName()); 37 | } 38 | 39 | if (!MIME_TYPE.equalsIgnoreCase(body.mimeType())) { 40 | throw new IllegalArgumentException("Expected a proto but was: " + body.mimeType()); 41 | } 42 | 43 | InputStream in = null; 44 | try { 45 | in = body.in(); 46 | return wire.parseFrom(in, (Class) c); 47 | } catch (IOException e) { 48 | throw new ConversionException(e); 49 | } finally { 50 | if (in != null) { 51 | try { 52 | in.close(); 53 | } catch (IOException ignored) { 54 | } 55 | } 56 | } 57 | } 58 | 59 | @Override public TypedOutput toBody(Object object) { 60 | if (!(object instanceof Message)) { 61 | throw new IllegalArgumentException( 62 | "Expected a proto message but was " + (object != null ? object.getClass().getName() 63 | : "null")); 64 | } 65 | byte[] bytes = ((Message) object).toByteArray(); 66 | return new TypedByteArray(MIME_TYPE, bytes); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /retrofit/src/main/java/retrofit/RxSupport.java: -------------------------------------------------------------------------------- 1 | package retrofit; 2 | 3 | import java.util.concurrent.Executor; 4 | import java.util.concurrent.FutureTask; 5 | import rx.Observable; 6 | import rx.Subscriber; 7 | import rx.subscriptions.Subscriptions; 8 | 9 | /** 10 | * Utilities for supporting RxJava Observables. 11 | *

12 | * RxJava might not be on the available to use. Check {@link Platform#HAS_RX_JAVA} before calling. 13 | */ 14 | final class RxSupport { 15 | /** A callback into {@link RestAdapter} to actually invoke the request. */ 16 | interface Invoker { 17 | /** Invoke the request. The interceptor will be "tape" from the time of subscription. */ 18 | ResponseWrapper invoke(RequestInterceptor requestInterceptor); 19 | } 20 | 21 | private final Executor executor; 22 | private final ErrorHandler errorHandler; 23 | private final RequestInterceptor requestInterceptor; 24 | 25 | RxSupport(Executor executor, ErrorHandler errorHandler, RequestInterceptor requestInterceptor) { 26 | this.executor = executor; 27 | this.errorHandler = errorHandler; 28 | this.requestInterceptor = requestInterceptor; 29 | } 30 | 31 | Observable createRequestObservable(final Invoker invoker) { 32 | return Observable.create(new Observable.OnSubscribe() { 33 | @Override public void call(Subscriber subscriber) { 34 | RequestInterceptorTape interceptorTape = new RequestInterceptorTape(); 35 | requestInterceptor.intercept(interceptorTape); 36 | 37 | Runnable runnable = getRunnable(subscriber, invoker, interceptorTape); 38 | FutureTask task = new FutureTask(runnable, null); 39 | 40 | // Subscribe to the future task of the network call allowing unsubscription. 41 | subscriber.add(Subscriptions.from(task)); 42 | executor.execute(task); 43 | } 44 | }); 45 | } 46 | 47 | private Runnable getRunnable(final Subscriber subscriber, final Invoker invoker, 48 | final RequestInterceptorTape interceptorTape) { 49 | return new Runnable() { 50 | @Override public void run() { 51 | try { 52 | if (subscriber.isUnsubscribed()) { 53 | return; 54 | } 55 | ResponseWrapper wrapper = invoker.invoke(interceptorTape); 56 | subscriber.onNext(wrapper.responseBody); 57 | subscriber.onCompleted(); 58 | } catch (RetrofitError e) { 59 | subscriber.onError(errorHandler.handleError(e)); 60 | } 61 | } 62 | }; 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /website/static/jquery.smooth-scroll.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * Smooth Scroll - v1.4.10 - 2013-03-02 3 | * https://github.com/kswedberg/jquery-smooth-scroll 4 | * Copyright (c) 2013 Karl Swedberg 5 | * Licensed MIT (https://github.com/kswedberg/jquery-smooth-scroll/blob/master/LICENSE-MIT) 6 | */ 7 | (function(l){function t(l){return l.replace(/(:|\.)/g,"\\$1")}var e="1.4.10",o={exclude:[],excludeWithin:[],offset:0,direction:"top",scrollElement:null,scrollTarget:null,beforeScroll:function(){},afterScroll:function(){},easing:"swing",speed:400,autoCoefficent:2},r=function(t){var e=[],o=!1,r=t.dir&&"left"==t.dir?"scrollLeft":"scrollTop";return this.each(function(){if(this!=document&&this!=window){var t=l(this);t[r]()>0?e.push(this):(t[r](1),o=t[r]()>0,o&&e.push(this),t[r](0))}}),e.length||this.each(function(){"BODY"===this.nodeName&&(e=[this])}),"first"===t.el&&e.length>1&&(e=[e[0]]),e};l.fn.extend({scrollable:function(l){var t=r.call(this,{dir:l});return this.pushStack(t)},firstScrollable:function(l){var t=r.call(this,{el:"first",dir:l});return this.pushStack(t)},smoothScroll:function(e){e=e||{};var o=l.extend({},l.fn.smoothScroll.defaults,e),r=l.smoothScroll.filterPath(location.pathname);return this.unbind("click.smoothscroll").bind("click.smoothscroll",function(e){var n=this,s=l(this),c=o.exclude,i=o.excludeWithin,a=0,f=0,h=!0,u={},d=location.hostname===n.hostname||!n.hostname,m=o.scrollTarget||(l.smoothScroll.filterPath(n.pathname)||r)===r,p=t(n.hash);if(o.scrollTarget||d&&m&&p){for(;h&&c.length>a;)s.is(t(c[a++]))&&(h=!1);for(;h&&i.length>f;)s.closest(i[f++]).length&&(h=!1)}else h=!1;h&&(e.preventDefault(),l.extend(u,o,{scrollTarget:o.scrollTarget||p,link:n}),l.smoothScroll(u))}),this}}),l.smoothScroll=function(t,e){var o,r,n,s,c=0,i="offset",a="scrollTop",f={},h={};"number"==typeof t?(o=l.fn.smoothScroll.defaults,n=t):(o=l.extend({},l.fn.smoothScroll.defaults,t||{}),o.scrollElement&&(i="position","static"==o.scrollElement.css("position")&&o.scrollElement.css("position","relative"))),o=l.extend({link:null},o),a="left"==o.direction?"scrollLeft":a,o.scrollElement?(r=o.scrollElement,c=r[a]()):r=l("html, body").firstScrollable(),o.beforeScroll.call(r,o),n="number"==typeof t?t:e||l(o.scrollTarget)[i]()&&l(o.scrollTarget)[i]()[o.direction]||0,f[a]=n+c+o.offset,s=o.speed,"auto"===s&&(s=f[a]||r.scrollTop(),s/=o.autoCoefficent),h={duration:s,easing:o.easing,complete:function(){o.afterScroll.call(o.link,o)}},o.step&&(h.step=o.step),r.length?r.stop().animate(f,h):o.afterScroll.call(o.link,o)},l.smoothScroll.version=e,l.smoothScroll.filterPath=function(l){return l.replace(/^\//,"").replace(/(index|default).[a-zA-Z]{3,4}$/,"").replace(/\/$/,"")},l.fn.smoothScroll.defaults=o})(jQuery); -------------------------------------------------------------------------------- /retrofit-converters/protobuf-nano/src/main/java/retrofit/converter/NanoProtoConverter.java: -------------------------------------------------------------------------------- 1 | package retrofit.converter; 2 | 3 | import com.google.common.base.Objects; 4 | import com.google.common.io.ByteStreams; 5 | import com.google.common.reflect.TypeToken; 6 | import com.google.protobuf.nano.InvalidProtocolBufferNanoException; 7 | import com.google.protobuf.nano.MessageNano; 8 | 9 | import retrofit.mime.TypedByteArray; 10 | import retrofit.mime.TypedInput; 11 | import retrofit.mime.TypedOutput; 12 | 13 | import java.io.IOException; 14 | import java.lang.reflect.Type; 15 | 16 | /** A {@link Converter} that reads and writes Nano Protocol Buffers. */ 17 | public class NanoProtoConverter implements Converter { 18 | private static final String MIME_TYPE = "application/x-protobuf"; 19 | 20 | @Override 21 | public Object fromBody(final TypedInput body, final Type type) throws ConversionException { 22 | if (!Objects.equal(MIME_TYPE, body.mimeType())) { 23 | throw new ConversionException("Response content type was not a proto: " + body.mimeType()); 24 | } 25 | 26 | try { 27 | return MessageNano.mergeFrom(getNanoProtoInstance(type), getMessageByteArray(body)); 28 | } catch (InvalidProtocolBufferNanoException e) { 29 | throw new ConversionException("Nanoproto conversion failed", e); 30 | } 31 | } 32 | 33 | private MessageNano getNanoProtoInstance(final Type type) throws ConversionException { 34 | final TypeToken typeToken = TypeToken.of(type); 35 | if (!TypeToken.of(MessageNano.class).isAssignableFrom(typeToken)) { 36 | throw new IllegalArgumentException( 37 | "Expected a nanoproto message but was " + typeToken.toString()); 38 | } 39 | 40 | try { 41 | return (MessageNano) typeToken.getRawType().newInstance(); 42 | } catch (InstantiationException e) { 43 | throw new ConversionException("Nanoproto instantiation failed", e); 44 | } catch (IllegalAccessException e) { 45 | throw new IllegalStateException(e); 46 | } 47 | } 48 | 49 | private byte[] getMessageByteArray(final TypedInput body) throws ConversionException { 50 | try { 51 | return ByteStreams.toByteArray(body.in()); 52 | } catch (IOException e) { 53 | throw new ConversionException("Reading nanoproto failed", e); 54 | } 55 | } 56 | 57 | @Override 58 | public TypedOutput toBody(final Object object) { 59 | if (!(object instanceof MessageNano)) { 60 | throw new IllegalArgumentException( 61 | "Expected a nanoproto but was " + object.getClass().getName()); 62 | } 63 | return new TypedByteArray(MIME_TYPE, MessageNano.toByteArray((MessageNano) object)); 64 | } 65 | 66 | } 67 | -------------------------------------------------------------------------------- /retrofit/src/main/java/retrofit/client/Response.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2013 Square, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package retrofit.client; 17 | 18 | import java.util.ArrayList; 19 | import java.util.Collections; 20 | import java.util.List; 21 | import retrofit.mime.TypedInput; 22 | 23 | /** 24 | * An HTTP response. 25 | *

26 | * When used directly as a data type for an interface method, the response body is buffered to a 27 | * {@code byte[]}. Annotate the method with {@link retrofit.http.Streaming @Streaming} for an 28 | * unbuffered stream from the network. 29 | */ 30 | public final class Response { 31 | private final String url; 32 | private final int status; 33 | private final String reason; 34 | private final List

headers; 35 | private final TypedInput body; 36 | 37 | public Response(String url, int status, String reason, List
headers, TypedInput body) { 38 | if (url == null) { 39 | throw new IllegalArgumentException("url == null"); 40 | } 41 | if (status < 200) { 42 | throw new IllegalArgumentException("Invalid status code: " + status); 43 | } 44 | if (reason == null) { 45 | throw new IllegalArgumentException("reason == null"); 46 | } 47 | if (headers == null) { 48 | throw new IllegalArgumentException("headers == null"); 49 | } 50 | 51 | this.url = url; 52 | this.status = status; 53 | this.reason = reason; 54 | this.headers = Collections.unmodifiableList(new ArrayList
(headers)); 55 | this.body = body; 56 | } 57 | 58 | /** Request URL. */ 59 | public String getUrl() { 60 | return url; 61 | } 62 | 63 | /** Status line code. */ 64 | public int getStatus() { 65 | return status; 66 | } 67 | 68 | /** Status line reason phrase. */ 69 | public String getReason() { 70 | return reason; 71 | } 72 | 73 | /** An unmodifiable collection of headers. */ 74 | public List
getHeaders() { 75 | return headers; 76 | } 77 | 78 | /** Response body. May be {@code null}. */ 79 | public TypedInput getBody() { 80 | return body; 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /retrofit/src/main/java/retrofit/mime/TypedByteArray.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2010 Square, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package retrofit.mime; 17 | 18 | import java.io.ByteArrayInputStream; 19 | import java.io.IOException; 20 | import java.io.InputStream; 21 | import java.io.OutputStream; 22 | import java.util.Arrays; 23 | 24 | /** 25 | * Byte array and its mime type. 26 | * 27 | * @author Bob Lee (bob@squareup.com) 28 | */ 29 | public class TypedByteArray implements TypedInput, TypedOutput { 30 | private final String mimeType; 31 | private final byte[] bytes; 32 | 33 | /** 34 | * Constructs a new typed byte array. Sets mimeType to {@code application/unknown} if absent. 35 | * 36 | * @throws NullPointerException if bytes are null 37 | */ 38 | public TypedByteArray(String mimeType, byte[] bytes) { 39 | if (mimeType == null) { 40 | mimeType = "application/unknown"; 41 | } 42 | if (bytes == null) { 43 | throw new NullPointerException("bytes"); 44 | } 45 | this.mimeType = mimeType; 46 | this.bytes = bytes; 47 | } 48 | 49 | public byte[] getBytes() { 50 | return bytes; 51 | } 52 | 53 | @Override public String fileName() { 54 | return null; 55 | } 56 | 57 | @Override public String mimeType() { 58 | return mimeType; 59 | } 60 | 61 | @Override public long length() { 62 | return bytes.length; 63 | } 64 | 65 | @Override public void writeTo(OutputStream out) throws IOException { 66 | out.write(bytes); 67 | } 68 | 69 | @Override public InputStream in() throws IOException { 70 | return new ByteArrayInputStream(bytes); 71 | } 72 | 73 | @Override public boolean equals(Object o) { 74 | if (this == o) return true; 75 | if (o == null || getClass() != o.getClass()) return false; 76 | 77 | TypedByteArray that = (TypedByteArray) o; 78 | 79 | if (!Arrays.equals(bytes, that.bytes)) return false; 80 | if (!mimeType.equals(that.mimeType)) return false; 81 | 82 | return true; 83 | } 84 | 85 | @Override public int hashCode() { 86 | int result = mimeType.hashCode(); 87 | result = 31 * result + Arrays.hashCode(bytes); 88 | return result; 89 | } 90 | 91 | @Override public String toString() { 92 | return "TypedByteArray[length=" + length() + "]"; 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /retrofit/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 4.0.0 5 | 6 | 7 | com.squareup.retrofit 8 | parent 9 | 1.6.2-SNAPSHOT 10 | ../pom.xml 11 | 12 | 13 | retrofit 14 | Retrofit 15 | 16 | 17 | 18 | com.google.code.gson 19 | gson 20 | 21 | 22 | 23 | com.google.android 24 | android 25 | true 26 | 27 | 28 | com.squareup.okhttp 29 | okhttp 30 | true 31 | 32 | 33 | com.squareup.okhttp 34 | okhttp-urlconnection 35 | true 36 | 37 | 38 | com.netflix.rxjava 39 | rxjava-core 40 | true 41 | 42 | 43 | com.google.appengine 44 | appengine-api-1.0-sdk 45 | true 46 | 47 | 48 | 49 | junit 50 | junit 51 | test 52 | 53 | 54 | org.assertj 55 | assertj-core 56 | test 57 | 58 | 59 | org.mockito 60 | mockito-core 61 | test 62 | 63 | 64 | com.google.guava 65 | guava 66 | test 67 | 68 | 69 | com.squareup.okhttp 70 | mockwebserver 71 | test 72 | 73 | 74 | 75 | 76 | 77 | 78 | org.apache.maven.plugins 79 | maven-compiler-plugin 80 | 81 | 82 | -proc:none 83 | 84 | 85 | 86 | 87 | 88 | -------------------------------------------------------------------------------- /retrofit/src/main/java/retrofit/RequestInterceptorTape.java: -------------------------------------------------------------------------------- 1 | package retrofit; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | /** 7 | * Records methods called against it as a RequestFacade and replays them when called as a 8 | * RequestInterceptor. 9 | */ 10 | final class RequestInterceptorTape implements RequestInterceptor.RequestFacade, RequestInterceptor { 11 | 12 | private final List tape = new ArrayList(); 13 | 14 | @Override public void addHeader(String name, String value) { 15 | tape.add(new CommandWithParams(Command.ADD_HEADER, name, value)); 16 | } 17 | 18 | @Override public void addPathParam(String name, String value) { 19 | tape.add(new CommandWithParams(Command.ADD_PATH_PARAM, name, value)); 20 | } 21 | 22 | @Override public void addEncodedPathParam(String name, String value) { 23 | tape.add(new CommandWithParams(Command.ADD_ENCODED_PATH_PARAM, name, value)); 24 | } 25 | 26 | @Override public void addQueryParam(String name, String value) { 27 | tape.add(new CommandWithParams(Command.ADD_QUERY_PARAM, name, value)); 28 | } 29 | 30 | @Override public void addEncodedQueryParam(String name, String value) { 31 | tape.add(new CommandWithParams(Command.ADD_ENCODED_QUERY_PARAM, name, value)); 32 | } 33 | 34 | @Override public void intercept(RequestFacade request) { 35 | for (CommandWithParams cwp : tape) { 36 | cwp.command.intercept(request, cwp.name, cwp.value); 37 | } 38 | } 39 | 40 | private enum Command { 41 | ADD_HEADER { 42 | @Override 43 | public void intercept(RequestFacade facade, String name, String value) { 44 | facade.addHeader(name, value); 45 | } 46 | }, 47 | ADD_PATH_PARAM { 48 | @Override 49 | public void intercept(RequestFacade facade, String name, String value) { 50 | facade.addPathParam(name, value); 51 | } 52 | }, 53 | ADD_ENCODED_PATH_PARAM { 54 | @Override 55 | public void intercept(RequestFacade facade, String name, String value) { 56 | facade.addEncodedPathParam(name, value); 57 | } 58 | }, 59 | ADD_QUERY_PARAM { 60 | @Override 61 | public void intercept(RequestFacade facade, String name, String value) { 62 | facade.addQueryParam(name, value); 63 | } 64 | }, 65 | ADD_ENCODED_QUERY_PARAM { 66 | @Override 67 | public void intercept(RequestFacade facade, String name, String value) { 68 | facade.addEncodedQueryParam(name, value); 69 | } 70 | }; 71 | 72 | abstract void intercept(RequestFacade facade, String name, String value); 73 | } 74 | 75 | private static final class CommandWithParams { 76 | final Command command; 77 | final String name; 78 | final String value; 79 | 80 | CommandWithParams(Command command, String name, String value) { 81 | this.command = command; 82 | this.name = name; 83 | this.value = value; 84 | } 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /retrofit/src/test/java/retrofit/client/ClientIntegrationTest.java: -------------------------------------------------------------------------------- 1 | //// Copyright 2014 Square, Inc. 2 | //package retrofit.client; 3 | // 4 | //import com.squareup.okhttp.mockwebserver.MockResponse; 5 | //import com.squareup.okhttp.mockwebserver.MockWebServer; 6 | //import com.squareup.okhttp.mockwebserver.RecordedRequest; 7 | //import java.io.IOException; 8 | //import java.util.Arrays; 9 | //import java.util.List; 10 | //import org.junit.After; 11 | //import org.junit.Before; 12 | //import org.junit.Test; 13 | //import org.junit.runner.RunWith; 14 | //import org.junit.runners.Parameterized; 15 | //import retrofit.RestAdapter; 16 | //import retrofit.http.Body; 17 | //import retrofit.http.GET; 18 | //import retrofit.http.POST; 19 | // 20 | //import static org.assertj.core.api.Assertions.assertThat; 21 | // 22 | //@RunWith(Parameterized.class) 23 | //public class ClientIntegrationTest { 24 | // @Parameterized.Parameters 25 | // public static List clients() { 26 | // return Arrays.asList(new Object[][] { 27 | // { new OkClient() }, 28 | // { new UrlConnectionClient() }, 29 | // { new ApacheClient() } 30 | // }); 31 | // } 32 | // 33 | // private final Client client; 34 | // 35 | // private MockWebServer server; 36 | // private Service service; 37 | // 38 | // public ClientIntegrationTest(Client client) { 39 | // this.client = client; 40 | // } 41 | // 42 | // @Before public void setUp() throws Exception { 43 | // server = new MockWebServer(); 44 | // server.play(); 45 | // 46 | // RestAdapter restAdapter = new RestAdapter.Builder() 47 | // .setEndpoint("http://" + server.getHostName() + ":" + server.getPort()) 48 | // .setClient(client) 49 | // .build(); 50 | // service = restAdapter.create(Service.class); 51 | // } 52 | // 53 | // @After public void tearDown() throws IOException { 54 | // server.shutdown(); 55 | // } 56 | // 57 | // private interface Service { 58 | // @GET("/get") 59 | // Response get(); 60 | // 61 | // @POST("/post") 62 | // Response post(@Body List body); 63 | // } 64 | // 65 | // @Test public void get() throws InterruptedException { 66 | // server.enqueue(new MockResponse().setBody("{}")); 67 | // service.get(); 68 | // 69 | // RecordedRequest request = server.takeRequest(); 70 | // assertThat(request.getPath()).isEqualTo("/get"); 71 | // assertThat(request.getBody()).isEmpty(); 72 | // } 73 | // 74 | // @Test public void post() throws InterruptedException { 75 | // server.enqueue(new MockResponse().setBody("{}")); 76 | // service.post(Arrays.asList("Hello", "World!")); 77 | // 78 | // RecordedRequest request = server.takeRequest(); 79 | // assertThat(request.getPath()).isEqualTo("/post"); 80 | // assertThat(request.getHeader("Content-Type")).isEqualTo("application/json; charset=UTF-8"); 81 | // assertThat(request.getHeader("Content-Length")).isEqualTo("18"); 82 | // assertThat(request.getUtf8Body()).isEqualTo("[\"Hello\",\"World!\"]"); 83 | // } 84 | //} 85 | -------------------------------------------------------------------------------- /retrofit-converters/jackson/src/test/java/retrofit/converter/JacksonConverterTest.java: -------------------------------------------------------------------------------- 1 | package retrofit.converter; 2 | 3 | import com.fasterxml.jackson.annotation.JsonProperty; 4 | import java.io.ByteArrayOutputStream; 5 | import org.junit.Test; 6 | import retrofit.mime.TypedByteArray; 7 | import retrofit.mime.TypedInput; 8 | import retrofit.mime.TypedOutput; 9 | 10 | import static org.assertj.core.api.Assertions.assertThat; 11 | 12 | public class JacksonConverterTest { 13 | private static final String MIME_TYPE = "application/json; charset=UTF-8"; 14 | private static final MyObject OBJECT = new MyObject("hello world", 10); 15 | private final String JSON = "{\"message\":\"hello world\",\"count\":10}"; 16 | 17 | private final JacksonConverter converter = new JacksonConverter(); 18 | 19 | @Test public void serialize() throws Exception { 20 | TypedOutput typedOutput = converter.toBody(OBJECT); 21 | assertThat(typedOutput.mimeType()).isEqualTo(MIME_TYPE); 22 | assertThat(asString(typedOutput)).isEqualTo(JSON); 23 | } 24 | 25 | @Test public void deserialize() throws Exception { 26 | TypedInput input = new TypedByteArray(MIME_TYPE, JSON.getBytes()); 27 | MyObject result = (MyObject) converter.fromBody(input, MyObject.class); 28 | assertThat(result).isEqualTo(OBJECT); 29 | } 30 | 31 | @Test(expected = ConversionException.class) 32 | public void deserializeWrongValue() throws Exception { 33 | TypedInput input = new TypedByteArray(MIME_TYPE, "{\"foo\":\"bar\"}".getBytes()); 34 | converter.fromBody(input, MyObject.class); 35 | } 36 | 37 | @Test(expected = ConversionException.class) 38 | public void deserializeWrongClass() throws Exception { 39 | TypedInput input = new TypedByteArray(MIME_TYPE, JSON.getBytes()); 40 | converter.fromBody(input, String.class); 41 | } 42 | 43 | private String asString(TypedOutput typedOutput) throws Exception { 44 | ByteArrayOutputStream bytes = new ByteArrayOutputStream(); 45 | typedOutput.writeTo(bytes); 46 | return new String(bytes.toByteArray()); 47 | } 48 | 49 | static class MyObject { 50 | private final String message; 51 | private final int count; 52 | 53 | public MyObject(@JsonProperty("message") String message, @JsonProperty("count") int count) { 54 | this.message = message; 55 | this.count = count; 56 | } 57 | 58 | public String getMessage() { 59 | return message; 60 | } 61 | 62 | public int getCount() { 63 | return count; 64 | } 65 | 66 | @Override public boolean equals(Object o) { 67 | if (this == o) return true; 68 | if (o == null || getClass() != o.getClass()) return false; 69 | 70 | MyObject myObject = (MyObject) o; 71 | return count == myObject.count 72 | && !(message != null ? !message.equals(myObject.message) : myObject.message != null); 73 | } 74 | 75 | @Override public int hashCode() { 76 | int result = message != null ? message.hashCode() : 0; 77 | result = 31 * result + count; 78 | return result; 79 | } 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /retrofit/src/test/java/retrofit/mime/MultipartTypedOutputTest.java: -------------------------------------------------------------------------------- 1 | // Copyright 2013 Square, Inc. 2 | package retrofit.mime; 3 | 4 | import java.io.ByteArrayOutputStream; 5 | import org.junit.Test; 6 | 7 | import static org.assertj.core.api.Assertions.assertThat; 8 | 9 | public class MultipartTypedOutputTest { 10 | @Test public void singlePart() throws Exception { 11 | String expected = "" // 12 | + "--123\r\n" 13 | + "Content-Disposition: form-data; name=\"greet\"\r\n" 14 | + "Content-Type: text/plain; charset=UTF-8\r\n" 15 | + "Content-Length: 13\r\n" 16 | + "Content-Transfer-Encoding: binary\r\n" // 17 | + "\r\n" // 18 | + "Hello, World!\r\n" // 19 | + "--123--\r\n"; 20 | 21 | MultipartTypedOutput mto = new MultipartTypedOutput("123"); 22 | mto.addPart("greet", new TypedString("Hello, World!")); 23 | 24 | ByteArrayOutputStream out = new ByteArrayOutputStream(); 25 | mto.writeTo(out); 26 | String actual = new String(out.toByteArray(), "UTF-8"); 27 | assertThat(actual).isEqualTo(expected); 28 | assertThat(mto.mimeType()).isEqualTo("multipart/form-data; boundary=123"); 29 | } 30 | 31 | @Test public void threeParts() throws Exception { 32 | String expected = "" 33 | + "--123\r\n" 34 | + "Content-Disposition: form-data; name=\"quick\"\r\n" 35 | + "Content-Type: text/plain; charset=UTF-8\r\n" 36 | + "Content-Length: 5\r\n" 37 | + "Content-Transfer-Encoding: binary\r\n" 38 | + "\r\n" 39 | + "brown\r\n" 40 | + "--123\r\n" 41 | + "Content-Disposition: form-data; name=\"fox\"\r\n" 42 | + "Content-Type: text/plain; charset=UTF-8\r\n" 43 | + "Content-Length: 5\r\n" 44 | + "Content-Transfer-Encoding: binary\r\n" 45 | + "\r\n" 46 | + "jumps\r\n" 47 | + "--123\r\n" 48 | + "Content-Disposition: form-data; name=\"lazy\"\r\n" 49 | + "Content-Type: text/plain; charset=UTF-8\r\n" 50 | + "Content-Length: 3\r\n" 51 | + "Content-Transfer-Encoding: binary\r\n" 52 | + "\r\n" 53 | + "dog\r\n" 54 | + "--123--\r\n"; 55 | 56 | MultipartTypedOutput mto = new MultipartTypedOutput("123"); 57 | mto.addPart("quick", new TypedString("brown")); 58 | mto.addPart("fox", new TypedString("jumps")); 59 | mto.addPart("lazy", new TypedString("dog")); 60 | 61 | ByteArrayOutputStream out = new ByteArrayOutputStream(); 62 | mto.writeTo(out); 63 | String actual = new String(out.toByteArray(), "UTF-8"); 64 | assertThat(actual).isEqualTo(expected); 65 | assertThat(mto.mimeType()).isEqualTo("multipart/form-data; boundary=123"); 66 | } 67 | 68 | @Test public void withPartOfUnknownLength() throws Exception { 69 | MultipartTypedOutput mto = new MultipartTypedOutput("123"); 70 | 71 | mto.addPart("first", new TypedString("value")); 72 | mto.addPart("second", new TypedString("unknown size") { 73 | @Override public long length() { 74 | return -1; 75 | } 76 | }); 77 | 78 | assertThat(mto.length()).isEqualTo(-1); 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /retrofit/src/main/java/retrofit/Profiler.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2012 Square, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package retrofit; 17 | 18 | /** 19 | * A hook allowing clients to log HTTP method times and response status codes. 20 | * 21 | * @author Eric Burke (eric@squareup.com) 22 | */ 23 | public interface Profiler { 24 | 25 | /** 26 | * Invoked before an HTTP method call. The object returned by this method will be 27 | * passed to {@link #afterCall} when the call returns. 28 | *

29 | * This method gives implementers the opportunity to include information that may 30 | * change during the server call in {@code afterCall} logic. 31 | */ 32 | T beforeCall(); 33 | 34 | /** 35 | * Invoked after an HTTP method completes. This is called from the 36 | * RestAdapter's background thread. 37 | * 38 | * @param requestInfo information about the originating HTTP request. 39 | * @param elapsedTime time in milliseconds it took the HTTP request to complete. 40 | * @param statusCode response status code. 41 | * @param beforeCallData the data returned by the corresponding {@link #beforeCall()}. 42 | */ 43 | void afterCall(RequestInformation requestInfo, long elapsedTime, int statusCode, 44 | T beforeCallData); 45 | 46 | /** Information about the HTTP request. */ 47 | public static final class RequestInformation { 48 | private final String method; 49 | private final String baseUrl; 50 | private final String relativePath; 51 | private final long contentLength; 52 | private final String contentType; 53 | 54 | public RequestInformation(String method, String baseUrl, String relativePath, 55 | long contentLength, String contentType) { 56 | this.method = method; 57 | this.baseUrl = baseUrl; 58 | this.relativePath = relativePath; 59 | this.contentLength = contentLength; 60 | this.contentType = contentType; 61 | } 62 | 63 | /** Returns the HTTP method of the originating request. */ 64 | public String getMethod() { 65 | return method; 66 | } 67 | 68 | /** Returns the URL to which the originating request was sent. */ 69 | public String getBaseUrl() { 70 | return baseUrl; 71 | } 72 | 73 | /** Returns the path relative to the base URL to which the originating request was sent. */ 74 | public String getRelativePath() { 75 | return relativePath; 76 | } 77 | 78 | /** Returns the number of bytes in the originating request. */ 79 | public long getContentLength() { 80 | return contentLength; 81 | } 82 | 83 | /** Returns the content type header value of the originating request. */ 84 | public String getContentType() { 85 | return contentType; 86 | } 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /retrofit/src/main/java/retrofit/ExceptionCatchingTypedInput.java: -------------------------------------------------------------------------------- 1 | package retrofit; 2 | 3 | import java.io.IOException; 4 | import java.io.InputStream; 5 | import retrofit.mime.TypedInput; 6 | 7 | class ExceptionCatchingTypedInput implements TypedInput { 8 | private final TypedInput delegate; 9 | private final ExceptionCatchingInputStream delegateStream; 10 | 11 | ExceptionCatchingTypedInput(TypedInput delegate) throws IOException { 12 | this.delegate = delegate; 13 | this.delegateStream = new ExceptionCatchingInputStream(delegate.in()); 14 | } 15 | 16 | @Override public String mimeType() { 17 | return delegate.mimeType(); 18 | } 19 | 20 | @Override public long length() { 21 | return delegate.length(); 22 | } 23 | 24 | @Override public InputStream in() throws IOException { 25 | return delegateStream; 26 | } 27 | 28 | IOException getThrownException() { 29 | return delegateStream.thrownException; 30 | } 31 | 32 | boolean threwException() { 33 | return delegateStream.thrownException != null; 34 | } 35 | 36 | private static class ExceptionCatchingInputStream extends InputStream { 37 | private final InputStream delegate; 38 | private IOException thrownException; 39 | 40 | ExceptionCatchingInputStream(InputStream delegate) { 41 | this.delegate = delegate; 42 | } 43 | 44 | @Override public int read() throws IOException { 45 | try { 46 | return delegate.read(); 47 | } catch (IOException e) { 48 | thrownException = e; 49 | throw e; 50 | } 51 | } 52 | 53 | @Override public int read(byte[] buffer) throws IOException { 54 | try { 55 | return delegate.read(buffer); 56 | } catch (IOException e) { 57 | thrownException = e; 58 | throw e; 59 | } 60 | } 61 | 62 | @Override public int read(byte[] buffer, int offset, int length) throws IOException { 63 | try { 64 | return delegate.read(buffer, offset, length); 65 | } catch (IOException e) { 66 | thrownException = e; 67 | throw e; 68 | } 69 | } 70 | 71 | @Override public long skip(long byteCount) throws IOException { 72 | try { 73 | return delegate.skip(byteCount); 74 | } catch (IOException e) { 75 | thrownException = e; 76 | throw e; 77 | } 78 | } 79 | 80 | @Override public int available() throws IOException { 81 | try { 82 | return delegate.available(); 83 | } catch (IOException e) { 84 | thrownException = e; 85 | throw e; 86 | } 87 | } 88 | 89 | @Override public void close() throws IOException { 90 | try { 91 | delegate.close(); 92 | } catch (IOException e) { 93 | thrownException = e; 94 | throw e; 95 | } 96 | } 97 | 98 | @Override public synchronized void mark(int readLimit) { 99 | delegate.mark(readLimit); 100 | } 101 | 102 | @Override public synchronized void reset() throws IOException { 103 | try { 104 | delegate.reset(); 105 | } catch (IOException e) { 106 | thrownException = e; 107 | throw e; 108 | } 109 | } 110 | 111 | @Override public boolean markSupported() { 112 | return delegate.markSupported(); 113 | } 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /retrofit-converters/wire/src/test/java/retrofit/converter/WireConverterTest.java: -------------------------------------------------------------------------------- 1 | // Copyright 2013 Square, Inc. 2 | package retrofit.converter; 3 | 4 | import com.google.common.io.BaseEncoding; 5 | import com.squareup.wire.Wire; 6 | import java.io.ByteArrayOutputStream; 7 | import java.io.IOException; 8 | import java.io.UnsupportedEncodingException; 9 | import java.util.ArrayList; 10 | import org.junit.Test; 11 | import retrofit.mime.TypedByteArray; 12 | import retrofit.mime.TypedOutput; 13 | 14 | import static org.assertj.core.api.Assertions.assertThat; 15 | import static org.junit.Assert.fail; 16 | 17 | public final class WireConverterTest { 18 | private static final Person PROTO = 19 | new Person.Builder().id(42).name("Omar Little").email("omar@theking.org").build(); 20 | private static final String PROTO_ENCODED = "CgtPbWFyIExpdHRsZRAqGhBvbWFyQHRoZWtpbmcub3Jn"; 21 | 22 | private WireConverter converter = new WireConverter(new Wire()); 23 | 24 | @Test public void serialize() throws Exception { 25 | TypedOutput protoBytes = converter.toBody(PROTO); 26 | assertThat(protoBytes.mimeType()).isEqualTo("application/x-protobuf"); 27 | assertThat(bytesOf(protoBytes)).isEqualTo(bytesOf(decodeBase64(PROTO_ENCODED))); 28 | } 29 | 30 | @Test public void deserialize() throws Exception { 31 | Object proto = converter.fromBody(decodeBase64(PROTO_ENCODED), Person.class); 32 | assertThat(proto).isEqualTo(PROTO); 33 | } 34 | 35 | @Test public void deserializeWrongClass() throws Exception { 36 | try { 37 | converter.fromBody(decodeBase64(PROTO_ENCODED), String.class); 38 | fail(); 39 | } catch (IllegalArgumentException e) { 40 | assertThat(e).hasMessage("Expected a proto message but was java.lang.String"); 41 | } 42 | } 43 | 44 | @Test public void deserializeWrongType() throws Exception { 45 | try { 46 | converter.fromBody(decodeBase64(PROTO_ENCODED), 47 | ArrayList.class.getGenericSuperclass()); 48 | fail(); 49 | } catch (IllegalArgumentException e) { 50 | assertThat(e).hasMessage("Expected a raw Class but was java.util.AbstractList"); 51 | } 52 | } 53 | 54 | @Test public void deserializeWrongValue() throws Exception { 55 | try { 56 | converter.fromBody(decodeBase64("////"), Person.class); 57 | fail(); 58 | } catch (ConversionException expected) { 59 | assertThat(expected.getCause()).isInstanceOf(IOException.class); 60 | } 61 | } 62 | 63 | @Test public void deserializeWrongMime() throws Exception { 64 | try { 65 | converter.fromBody(decodeBase64("////", "yummy/bytes"), Person.class); 66 | fail(); 67 | } catch (IllegalArgumentException e) { 68 | assertThat(e).hasMessage("Expected a proto but was: yummy/bytes"); 69 | } 70 | } 71 | 72 | private static byte[] bytesOf(TypedOutput protoBytes) throws IOException { 73 | ByteArrayOutputStream bytes = new ByteArrayOutputStream(); 74 | protoBytes.writeTo(bytes); 75 | return bytes.toByteArray(); 76 | } 77 | 78 | private static TypedByteArray decodeBase64(String base64) throws UnsupportedEncodingException { 79 | return decodeBase64(base64, "application/x-protobuf"); 80 | } 81 | 82 | private static TypedByteArray decodeBase64(String base64, String mime) throws UnsupportedEncodingException { 83 | return new TypedByteArray(mime, BaseEncoding.base64().decode(base64)); 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /retrofit-converters/protobuf/src/test/java/retrofit/converter/ProtoConverterTest.java: -------------------------------------------------------------------------------- 1 | // Copyright 2013 Square, Inc. 2 | package retrofit.converter; 3 | 4 | import com.google.common.io.BaseEncoding; 5 | import com.google.protobuf.InvalidProtocolBufferException; 6 | import java.io.ByteArrayOutputStream; 7 | import java.io.IOException; 8 | import java.io.UnsupportedEncodingException; 9 | import java.util.ArrayList; 10 | import org.junit.Test; 11 | import retrofit.mime.TypedByteArray; 12 | import retrofit.mime.TypedOutput; 13 | 14 | import static org.assertj.core.api.Assertions.assertThat; 15 | import static org.junit.Assert.fail; 16 | import static retrofit.converter.PhoneProtos.Phone; 17 | 18 | public final class ProtoConverterTest { 19 | private static final Phone PROTO = Phone.newBuilder().setNumber("(519) 867-5309").build(); 20 | private static final String ENCODED_PROTO = "Cg4oNTE5KSA4NjctNTMwOQ=="; 21 | 22 | private final ProtoConverter protoConverter = new ProtoConverter(); 23 | 24 | @Test public void serialize() throws Exception { 25 | TypedOutput protoBytes = protoConverter.toBody(PROTO); 26 | assertThat(protoBytes.mimeType()).isEqualTo("application/x-protobuf"); 27 | assertThat(bytesOf(protoBytes)).isEqualTo(bytesOf(decodeBase64(ENCODED_PROTO))); 28 | } 29 | 30 | @Test public void deserialize() throws Exception { 31 | Object proto = protoConverter.fromBody(decodeBase64(ENCODED_PROTO), Phone.class); 32 | assertThat(proto).isEqualTo(PROTO); 33 | } 34 | 35 | @Test public void deserializeWrongClass() throws Exception { 36 | try { 37 | protoConverter.fromBody(decodeBase64(ENCODED_PROTO), String.class); 38 | fail(); 39 | } catch (IllegalArgumentException e) { 40 | assertThat(e).hasMessage("Expected a protobuf message but was java.lang.String"); 41 | } 42 | } 43 | 44 | @Test public void deserializeWrongType() throws Exception { 45 | try { 46 | protoConverter.fromBody(decodeBase64(ENCODED_PROTO), ArrayList.class.getGenericSuperclass()); 47 | fail(); 48 | } catch (IllegalArgumentException e) { 49 | assertThat(e).hasMessage("Expected a raw Class but was java.util.AbstractList"); 50 | } 51 | } 52 | 53 | @Test public void deserializeWrongValue() throws Exception { 54 | try { 55 | protoConverter.fromBody(decodeBase64("////"), Phone.class); 56 | fail(); 57 | } catch (ConversionException expected) { 58 | assertThat(expected.getCause() instanceof InvalidProtocolBufferException); 59 | } 60 | } 61 | 62 | @Test public void deserializeWrongMime() throws Exception { 63 | try { 64 | protoConverter.fromBody(decodeBase64("////", "yummy/bytes"), Phone.class); 65 | fail(); 66 | } catch (ConversionException e) { 67 | assertThat(e).hasMessage("Response content type was not a proto: yummy/bytes"); 68 | } 69 | } 70 | 71 | private static byte[] bytesOf(TypedOutput protoBytes) throws IOException { 72 | ByteArrayOutputStream bytes = new ByteArrayOutputStream(); 73 | protoBytes.writeTo(bytes); 74 | return bytes.toByteArray(); 75 | } 76 | 77 | private static TypedByteArray decodeBase64(String base64) throws UnsupportedEncodingException { 78 | return decodeBase64(base64, "application/x-protobuf"); 79 | } 80 | 81 | private static TypedByteArray decodeBase64(String base64, String mime) throws UnsupportedEncodingException { 82 | return new TypedByteArray(mime, BaseEncoding.base64().decode(base64)); 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /retrofit-converters/protobuf-nano/src/test/java/retrofit/converter/NanoProtoConverterTest.java: -------------------------------------------------------------------------------- 1 | package retrofit.converter; 2 | 3 | import com.google.common.io.BaseEncoding; 4 | import com.google.protobuf.InvalidProtocolBufferException; 5 | import java.io.ByteArrayOutputStream; 6 | import java.io.IOException; 7 | import java.io.UnsupportedEncodingException; 8 | import java.util.ArrayList; 9 | import org.junit.Before; 10 | import org.junit.Test; 11 | import retrofit.mime.TypedByteArray; 12 | import retrofit.mime.TypedOutput; 13 | 14 | import static org.assertj.core.api.Assertions.assertThat; 15 | import static org.junit.Assert.fail; 16 | import static retrofit.converter.PhoneProtos.Phone; 17 | 18 | public final class NanoProtoConverterTest { 19 | private static final String ENCODED_PROTO = "Cg4oNTE5KSA4NjctNTMwOQ=="; 20 | 21 | private final NanoProtoConverter protoConverter = new NanoProtoConverter(); 22 | private final Phone proto = new Phone(); 23 | 24 | @Before public void setUp() { 25 | proto.number = "(519) 867-5309"; 26 | } 27 | 28 | @Test public void serialize() throws Exception { 29 | TypedOutput protoBytes = protoConverter.toBody(proto); 30 | assertThat(protoBytes.mimeType()).isEqualTo("application/x-protobuf"); 31 | assertThat(bytesOf(protoBytes)).isEqualTo(bytesOf(decodeBase64(ENCODED_PROTO))); 32 | } 33 | 34 | @Test public void deserialize() throws Exception { 35 | Object proto = protoConverter.fromBody(decodeBase64(ENCODED_PROTO), Phone.class); 36 | assertThat(proto).isEqualTo(proto); 37 | } 38 | 39 | @Test public void deserializeWrongClass() throws Exception { 40 | try { 41 | protoConverter.fromBody(decodeBase64(ENCODED_PROTO), String.class); 42 | fail(); 43 | } catch (IllegalArgumentException e) { 44 | assertThat(e).hasMessage("Expected a nanoproto message but was java.lang.String"); 45 | } 46 | } 47 | 48 | @Test public void deserializeWrongType() throws Exception { 49 | try { 50 | protoConverter.fromBody(decodeBase64(ENCODED_PROTO), ArrayList.class.getGenericSuperclass()); 51 | fail(); 52 | } catch (IllegalArgumentException e) { 53 | assertThat(e).hasMessage("Expected a nanoproto message but was java.util.AbstractList"); 54 | } 55 | } 56 | 57 | @Test public void deserializeWrongValue() throws Exception { 58 | try { 59 | protoConverter.fromBody(decodeBase64("////"), Phone.class); 60 | fail(); 61 | } catch (ConversionException expected) { 62 | assertThat(expected.getCause() instanceof InvalidProtocolBufferException); 63 | } 64 | } 65 | 66 | @Test public void deserializeWrongMime() throws Exception { 67 | try { 68 | protoConverter.fromBody(decodeBase64("////", "yummy/bytes"), Phone.class); 69 | fail(); 70 | } catch (ConversionException e) { 71 | assertThat(e).hasMessage("Response content type was not a proto: yummy/bytes"); 72 | } 73 | } 74 | 75 | private static byte[] bytesOf(TypedOutput protoBytes) throws IOException { 76 | ByteArrayOutputStream bytes = new ByteArrayOutputStream(); 77 | protoBytes.writeTo(bytes); 78 | return bytes.toByteArray(); 79 | } 80 | 81 | private static TypedByteArray decodeBase64(String base64) throws UnsupportedEncodingException { 82 | return decodeBase64(base64, "application/x-protobuf"); 83 | } 84 | 85 | private static TypedByteArray decodeBase64(String base64, String mime) throws UnsupportedEncodingException { 86 | return new TypedByteArray(mime, BaseEncoding.base64().decode(base64)); 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /retrofit/src/main/java/retrofit/mime/TypedFile.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2010 Square, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package retrofit.mime; 17 | 18 | import java.io.File; 19 | import java.io.FileInputStream; 20 | import java.io.IOException; 21 | import java.io.InputStream; 22 | import java.io.OutputStream; 23 | 24 | /** 25 | * File and its mime type. 26 | * 27 | * @author Bob Lee (bob@squareup.com) 28 | */ 29 | public class TypedFile implements TypedInput, TypedOutput { 30 | private static final int BUFFER_SIZE = 4096; 31 | 32 | private final String mimeType; 33 | private final File file; 34 | 35 | /** 36 | * Constructs a new typed file. 37 | * 38 | * @throws NullPointerException if file or mimeType is null 39 | */ 40 | public TypedFile(String mimeType, File file) { 41 | if (mimeType == null) { 42 | throw new NullPointerException("mimeType"); 43 | } 44 | if (file == null) { 45 | throw new NullPointerException("file"); 46 | } 47 | this.mimeType = mimeType; 48 | this.file = file; 49 | } 50 | 51 | /** Returns the file. */ 52 | public File file() { 53 | return file; 54 | } 55 | 56 | @Override public String mimeType() { 57 | return mimeType; 58 | } 59 | 60 | @Override public long length() { 61 | return file.length(); 62 | } 63 | 64 | @Override public String fileName() { 65 | return file.getName(); 66 | } 67 | 68 | @Override public InputStream in() throws IOException { 69 | return new FileInputStream(file); 70 | } 71 | 72 | @Override public void writeTo(OutputStream out) throws IOException { 73 | byte[] buffer = new byte[BUFFER_SIZE]; 74 | FileInputStream in = new FileInputStream(file); 75 | try { 76 | int read; 77 | while ((read = in.read(buffer)) != -1) { 78 | out.write(buffer, 0, read); 79 | } 80 | } finally { 81 | in.close(); 82 | } 83 | } 84 | 85 | /** 86 | * Atomically moves the contents of this file to a new location. 87 | * 88 | * @param destination file 89 | * @throws java.io.IOException if the move fails 90 | */ 91 | public void moveTo(TypedFile destination) throws IOException { 92 | if (!mimeType().equals(destination.mimeType())) { 93 | throw new IOException("Type mismatch."); 94 | } 95 | if (!file.renameTo(destination.file())) { 96 | throw new IOException("Rename failed!"); 97 | } 98 | } 99 | 100 | @Override public String toString() { 101 | return file.getAbsolutePath() + " (" + mimeType() + ")"; 102 | } 103 | 104 | @Override public boolean equals(Object o) { 105 | if (this == o) return true; 106 | if (o instanceof TypedFile) { 107 | TypedFile rhs = (TypedFile) o; 108 | return file.equals(rhs.file); 109 | } 110 | return false; 111 | } 112 | 113 | @Override public int hashCode() { 114 | return file.hashCode(); 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /website/static/app.css: -------------------------------------------------------------------------------- 1 | html, body { 2 | font-family: 'Roboto', sans-serif; 3 | font-size: 15px; 4 | } 5 | body { 6 | background-color: #f6f6f6; 7 | padding-bottom: 50px; 8 | padding-top: 80px; 9 | } 10 | 11 | header { 12 | min-height: 80px; 13 | color: #f6f6f6; 14 | position: fixed; 15 | top: 0; 16 | left: 0; 17 | width: 100%; 18 | z-index: 99; 19 | } 20 | header h1 { 21 | margin: 10px 0; 22 | font-size: 50px; 23 | line-height: 60px; 24 | font-weight: 100; 25 | text-rendering: auto; 26 | } 27 | header menu { 28 | margin: 20px 0 0; 29 | padding: 0; 30 | height: 40px; 31 | } 32 | header menu ul { 33 | margin: 0; 34 | padding: 0; 35 | float: right; 36 | } 37 | header menu li { 38 | list-style: none; 39 | float: left; 40 | margin: 0; 41 | padding: 0; 42 | } 43 | header menu li a { 44 | display: inline-block; 45 | height: 40px; 46 | font-size: 17px; 47 | line-height: 40px; 48 | padding: 0 20px; 49 | color: #f6f6f6; 50 | } 51 | header menu li a:hover { 52 | color: #f6f6f6; 53 | text-decoration: none; 54 | } 55 | header menu li a img { 56 | margin: 0; 57 | padding: 5px 0; 58 | vertical-align: bottom; 59 | width: 30px; 60 | height: 30px; 61 | } 62 | 63 | #subtitle { 64 | position: absolute; 65 | top: 80px; 66 | left: 0; 67 | width: 100%; 68 | } 69 | h2 { 70 | font-weight: 200; 71 | font-size: 26px; 72 | line-height: 30px; 73 | padding: 15px 0; 74 | margin: 0; 75 | color: #eee; 76 | } 77 | h2 strong { 78 | font-weight: 300; 79 | } 80 | 81 | a.dl { 82 | font-weight: 300; 83 | font-size: 30px; 84 | line-height: 40px; 85 | padding: 3px 10px; 86 | display: inline-block; 87 | border-radius: 6px; 88 | color: #f0f0f0; 89 | margin: 5px 0; 90 | } 91 | a.dl:hover { 92 | color: #f0f0f0; 93 | text-decoration: none; 94 | } 95 | 96 | .content-nav { 97 | margin-top: 130px; 98 | width: 220px; 99 | } 100 | .content-nav.affix { 101 | top: 0; 102 | } 103 | .content-nav li.active a, .content-nav li.active a:hover { 104 | background-color: transparent; 105 | color: #555; 106 | border-left-width: 2px; 107 | } 108 | .content-nav .secondary a { 109 | color: #aaa; 110 | } 111 | .content-nav .secondary a:hover { 112 | color: #888; 113 | } 114 | 115 | h3 { 116 | font-weight: 300; 117 | font-style: italic; 118 | color: #888; 119 | font-size: 20px; 120 | padding-top: 115px; 121 | margin-top: 0; 122 | } 123 | 124 | h4 { 125 | font-weight: 400; 126 | text-transform: uppercase; 127 | color: #888; 128 | font-size: 15px; 129 | padding-top: 20px; 130 | } 131 | 132 | p.license { 133 | font-family: fixed-width; 134 | } 135 | 136 | .row .logo { 137 | text-align: center; 138 | margin-top: 150px; 139 | } 140 | .row .logo img { 141 | height: 30px; 142 | } 143 | 144 | pre, code { 145 | color: #666; 146 | } 147 | code { 148 | border: 0; 149 | background-color: transparent; 150 | } 151 | 152 | /* Widescreen desktop. */ 153 | @media (min-width: 1200px) { 154 | .content-nav { 155 | width: 270px; 156 | } 157 | } 158 | 159 | /* Smaller width browser, tablets. */ 160 | @media (max-width: 979px) { 161 | .content-nav { 162 | width: 166px; 163 | } 164 | } 165 | 166 | /* One-column mobile display. */ 167 | @media (max-width: 767px) { 168 | header { 169 | position: absolute; 170 | top: 0; 171 | left: 0; 172 | width: 100%; 173 | padding-left: 20px; 174 | } 175 | header menu { 176 | display: none; 177 | } 178 | #subtitle { 179 | position: absolute; 180 | top: 80px; 181 | left: 0; 182 | width: 100%; 183 | padding-left: 20px; 184 | } 185 | .content-nav { 186 | display: none; 187 | } 188 | } -------------------------------------------------------------------------------- /retrofit/src/test/java/retrofit/client/DummyHttpUrlConnection.java: -------------------------------------------------------------------------------- 1 | // Copyright 2013 Square, Inc. 2 | package retrofit.client; 3 | 4 | import java.io.ByteArrayOutputStream; 5 | import java.io.IOException; 6 | import java.io.InputStream; 7 | import java.net.HttpURLConnection; 8 | import java.net.MalformedURLException; 9 | import java.net.URL; 10 | import java.util.ArrayList; 11 | import java.util.LinkedHashMap; 12 | import java.util.List; 13 | import java.util.Map; 14 | 15 | /** 16 | * Provides POJO behavior for all of the APIs {@link retrofit.client.UrlConnectionClient} 17 | * interacts with. 18 | */ 19 | public class DummyHttpUrlConnection extends HttpURLConnection { 20 | private final Map> responseHeaders = 21 | new LinkedHashMap>(); 22 | private final Map> requestHeaders = 23 | new LinkedHashMap>(); 24 | private final ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); 25 | private int responseCode; 26 | private String responseMessage; 27 | private InputStream inputStream; 28 | private InputStream errorStream; 29 | 30 | protected DummyHttpUrlConnection(String url) throws MalformedURLException { 31 | super(new URL(url)); 32 | } 33 | 34 | public void setResponseCode(int responseCode) { 35 | this.responseCode = responseCode; 36 | } 37 | 38 | @Override public int getResponseCode() throws IOException { 39 | return responseCode; 40 | } 41 | 42 | public void setResponseMessage(String responseMessage) { 43 | this.responseMessage = responseMessage; 44 | } 45 | 46 | @Override public String getResponseMessage() throws IOException { 47 | return responseMessage; 48 | } 49 | 50 | @Override public ByteArrayOutputStream getOutputStream() throws IOException { 51 | return outputStream; 52 | } 53 | 54 | public void setInputStream(InputStream inputStream) { 55 | this.inputStream = inputStream; 56 | } 57 | 58 | @Override public InputStream getInputStream() throws IOException { 59 | return inputStream; 60 | } 61 | 62 | public void setErrorStream(InputStream errorStream) { 63 | this.errorStream = errorStream; 64 | } 65 | 66 | @Override public InputStream getErrorStream() { 67 | return errorStream; 68 | } 69 | 70 | public void addResponseHeader(String name, String value) { 71 | List values = responseHeaders.get(name); 72 | if (values == null) { 73 | values = new ArrayList(); 74 | responseHeaders.put(name, values); 75 | } 76 | values.add(value); 77 | } 78 | 79 | @Override public Map> getHeaderFields() { 80 | return responseHeaders; 81 | } 82 | 83 | @Override public void addRequestProperty(String name, String value) { 84 | List values = requestHeaders.get(name); 85 | if (values == null) { 86 | values = new ArrayList(); 87 | requestHeaders.put(name, values); 88 | } 89 | values.add(value); 90 | } 91 | 92 | @Override public Map> getRequestProperties() { 93 | return requestHeaders; 94 | } 95 | 96 | @Override public String getRequestProperty(String name) { 97 | List values = requestHeaders.get(name); 98 | if (values == null || values.isEmpty()) { 99 | return null; 100 | } 101 | return values.get(0); 102 | } 103 | 104 | @Override public void disconnect() { 105 | throw new AssertionError("Not implemented."); 106 | } 107 | 108 | @Override public boolean usingProxy() { 109 | return false; 110 | } 111 | 112 | @Override public void connect() throws IOException { 113 | throw new AssertionError("Not implemented."); 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /retrofit/src/main/java/retrofit/converter/GsonConverter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2012 Square, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package retrofit.converter; 17 | 18 | import com.google.gson.Gson; 19 | import com.google.gson.JsonParseException; 20 | import java.io.IOException; 21 | import java.io.InputStreamReader; 22 | import java.io.OutputStream; 23 | import java.io.UnsupportedEncodingException; 24 | import java.lang.reflect.Type; 25 | import retrofit.mime.MimeUtil; 26 | import retrofit.mime.TypedInput; 27 | import retrofit.mime.TypedOutput; 28 | 29 | /** 30 | * A {@link Converter} which uses GSON for serialization and deserialization of entities. 31 | * 32 | * @author Jake Wharton (jw@squareup.com) 33 | */ 34 | public class GsonConverter implements Converter { 35 | private final Gson gson; 36 | private String encoding; 37 | 38 | /** 39 | * Create an instance using the supplied {@link Gson} object for conversion. Encoding to JSON and 40 | * decoding from JSON (when no charset is specified by a header) will use UTF-8. 41 | */ 42 | public GsonConverter(Gson gson) { 43 | this(gson, "UTF-8"); 44 | } 45 | 46 | /** 47 | * Create an instance using the supplied {@link Gson} object for conversion. Encoding to JSON and 48 | * decoding from JSON (when no charset is specified by a header) will use the specified encoding. 49 | */ 50 | public GsonConverter(Gson gson, String encoding) { 51 | this.gson = gson; 52 | this.encoding = encoding; 53 | } 54 | 55 | @Override public Object fromBody(TypedInput body, Type type) throws ConversionException { 56 | String charset = "UTF-8"; 57 | if (body.mimeType() != null) { 58 | charset = MimeUtil.parseCharset(body.mimeType()); 59 | } 60 | InputStreamReader isr = null; 61 | try { 62 | isr = new InputStreamReader(body.in(), charset); 63 | return gson.fromJson(isr, type); 64 | } catch (IOException e) { 65 | throw new ConversionException(e); 66 | } catch (JsonParseException e) { 67 | throw new ConversionException(e); 68 | } finally { 69 | if (isr != null) { 70 | try { 71 | isr.close(); 72 | } catch (IOException ignored) { 73 | } 74 | } 75 | } 76 | } 77 | 78 | @Override public TypedOutput toBody(Object object) { 79 | try { 80 | return new JsonTypedOutput(gson.toJson(object).getBytes(encoding), encoding); 81 | } catch (UnsupportedEncodingException e) { 82 | throw new AssertionError(e); 83 | } 84 | } 85 | 86 | private static class JsonTypedOutput implements TypedOutput { 87 | private final byte[] jsonBytes; 88 | private final String mimeType; 89 | 90 | JsonTypedOutput(byte[] jsonBytes, String encode) { 91 | this.jsonBytes = jsonBytes; 92 | this.mimeType = "application/json; charset=" + encode; 93 | } 94 | 95 | @Override public String fileName() { 96 | return null; 97 | } 98 | 99 | @Override public String mimeType() { 100 | return mimeType; 101 | } 102 | 103 | @Override public long length() { 104 | return jsonBytes.length; 105 | } 106 | 107 | @Override public void writeTo(OutputStream out) throws IOException { 108 | out.write(jsonBytes); 109 | } 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /retrofit/src/main/java/retrofit/appengine/UrlFetchClient.java: -------------------------------------------------------------------------------- 1 | package retrofit.appengine; 2 | 3 | import com.google.appengine.api.urlfetch.HTTPHeader; 4 | import com.google.appengine.api.urlfetch.HTTPMethod; 5 | import com.google.appengine.api.urlfetch.HTTPRequest; 6 | import com.google.appengine.api.urlfetch.HTTPResponse; 7 | import com.google.appengine.api.urlfetch.URLFetchService; 8 | import com.google.appengine.api.urlfetch.URLFetchServiceFactory; 9 | import java.io.ByteArrayOutputStream; 10 | import java.io.IOException; 11 | import java.net.URL; 12 | import java.util.ArrayList; 13 | import java.util.List; 14 | import retrofit.client.Client; 15 | import retrofit.client.Header; 16 | import retrofit.client.Request; 17 | import retrofit.client.Response; 18 | import retrofit.mime.TypedByteArray; 19 | import retrofit.mime.TypedOutput; 20 | 21 | /** A {@link Client} for Google AppEngine's which uses its {@link URLFetchService}. */ 22 | public class UrlFetchClient implements Client { 23 | private static HTTPMethod getHttpMethod(String method) { 24 | if ("GET".equals(method)) { 25 | return HTTPMethod.GET; 26 | } else if ("POST".equals(method)) { 27 | return HTTPMethod.POST; 28 | } else if ("PATCH".equals(method)) { 29 | return HTTPMethod.PATCH; 30 | } else if ("PUT".equals(method)) { 31 | return HTTPMethod.PUT; 32 | } else if ("DELETE".equals(method)) { 33 | return HTTPMethod.DELETE; 34 | } else if ("HEAD".equals(method)) { 35 | return HTTPMethod.HEAD; 36 | } else { 37 | throw new IllegalStateException("Illegal HTTP method: " + method); 38 | } 39 | } 40 | 41 | private final URLFetchService urlFetchService; 42 | 43 | public UrlFetchClient() { 44 | this(URLFetchServiceFactory.getURLFetchService()); 45 | } 46 | 47 | public UrlFetchClient(URLFetchService urlFetchService) { 48 | this.urlFetchService = urlFetchService; 49 | } 50 | 51 | @Override public Response execute(Request request) throws IOException { 52 | HTTPRequest fetchRequest = createRequest(request); 53 | HTTPResponse fetchResponse = execute(urlFetchService, fetchRequest); 54 | return parseResponse(fetchResponse); 55 | } 56 | 57 | /** Execute the specified {@code request} using the provided {@code urlFetchService}. */ 58 | protected HTTPResponse execute(URLFetchService urlFetchService, HTTPRequest request) 59 | throws IOException { 60 | return urlFetchService.fetch(request); 61 | } 62 | 63 | static HTTPRequest createRequest(Request request) throws IOException { 64 | HTTPMethod httpMethod = getHttpMethod(request.getMethod()); 65 | URL url = new URL(request.getUrl()); 66 | HTTPRequest fetchRequest = new HTTPRequest(url, httpMethod); 67 | 68 | for (Header header : request.getHeaders()) { 69 | fetchRequest.addHeader(new HTTPHeader(header.getName(), header.getValue())); 70 | } 71 | 72 | TypedOutput body = request.getBody(); 73 | if (body != null) { 74 | ByteArrayOutputStream baos = new ByteArrayOutputStream(); 75 | body.writeTo(baos); 76 | fetchRequest.setPayload(baos.toByteArray()); 77 | } 78 | 79 | return fetchRequest; 80 | } 81 | 82 | static Response parseResponse(HTTPResponse response) { 83 | String url = response.getFinalUrl().toString(); 84 | int status = response.getResponseCode(); 85 | 86 | List fetchHeaders = response.getHeaders(); 87 | List

headers = new ArrayList
(fetchHeaders.size()); 88 | String contentType = "application/octet-stream"; 89 | for (HTTPHeader fetchHeader : fetchHeaders) { 90 | String name = fetchHeader.getName(); 91 | String value = fetchHeader.getValue(); 92 | if ("Content-Type".equalsIgnoreCase(name)) { 93 | contentType = value; 94 | } 95 | headers.add(new Header(name, value)); 96 | } 97 | 98 | TypedByteArray body = null; 99 | byte[] fetchBody = response.getContent(); 100 | if (fetchBody != null) { 101 | body = new TypedByteArray(contentType, fetchBody); 102 | } 103 | 104 | return new Response(url, status, "", headers, body); 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /retrofit/src/main/java/retrofit/RetrofitError.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2012 Square, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package retrofit; 17 | 18 | import java.io.IOException; 19 | import java.lang.reflect.Type; 20 | import retrofit.client.Response; 21 | import retrofit.converter.ConversionException; 22 | import retrofit.converter.Converter; 23 | import retrofit.mime.TypedInput; 24 | 25 | public class RetrofitError extends RuntimeException { 26 | public static RetrofitError networkError(String url, IOException exception) { 27 | return new RetrofitError(exception.getMessage(), url, null, null, null, true, exception); 28 | } 29 | 30 | public static RetrofitError conversionError(String url, Response response, Converter converter, 31 | Type successType, ConversionException exception) { 32 | return new RetrofitError(exception.getMessage(), url, response, converter, successType, false, 33 | exception); 34 | } 35 | 36 | public static RetrofitError httpError(String url, Response response, Converter converter, 37 | Type successType) { 38 | String message = response.getStatus() + " " + response.getReason(); 39 | return new RetrofitError(message, url, response, converter, successType, false, null); 40 | } 41 | 42 | public static RetrofitError unexpectedError(String url, Throwable exception) { 43 | return new RetrofitError(exception.getMessage(), url, null, null, null, false, exception); 44 | } 45 | 46 | private final String url; 47 | private final Response response; 48 | private final Converter converter; 49 | private final Type successType; 50 | private final boolean networkError; 51 | 52 | RetrofitError(String message, String url, Response response, Converter converter, 53 | Type successType, boolean networkError, Throwable exception) { 54 | super(message, exception); 55 | this.url = url; 56 | this.response = response; 57 | this.converter = converter; 58 | this.successType = successType; 59 | this.networkError = networkError; 60 | } 61 | 62 | /** The request URL which produced the error. */ 63 | public String getUrl() { 64 | return url; 65 | } 66 | 67 | /** Response object containing status code, headers, body, etc. */ 68 | public Response getResponse() { 69 | return response; 70 | } 71 | 72 | /** Whether or not this error was the result of a network error. */ 73 | public boolean isNetworkError() { 74 | return networkError; 75 | } 76 | 77 | /** 78 | * HTTP response body converted to the type declared by either the interface method return type or 79 | * the generic type of the supplied {@link Callback} parameter. {@code null} if there is no 80 | * response. 81 | */ 82 | public Object getBody() { 83 | return getBodyAs(successType); 84 | } 85 | 86 | /** 87 | * The type declared by either the interface method return type or the generic type of the 88 | * supplied {@link Callback} parameter. 89 | */ 90 | public Type getSuccessType() { 91 | return successType; 92 | } 93 | 94 | /** 95 | * HTTP response body converted to specified {@code type}. {@code null} if there is no response. 96 | */ 97 | public Object getBodyAs(Type type) { 98 | if (response == null) { 99 | return null; 100 | } 101 | TypedInput body = response.getBody(); 102 | if (body == null) { 103 | return null; 104 | } 105 | try { 106 | return converter.fromBody(body, type); 107 | } catch (ConversionException e) { 108 | throw new RuntimeException(e); 109 | } 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /retrofit/src/test/java/retrofit/ErrorHandlerTest.java: -------------------------------------------------------------------------------- 1 | // Copyright 2013 Square, Inc. 2 | package retrofit; 3 | 4 | import java.io.IOException; 5 | import java.util.Collections; 6 | import org.junit.Before; 7 | import org.junit.Test; 8 | import retrofit.client.Client; 9 | import retrofit.client.Header; 10 | import retrofit.client.Request; 11 | import retrofit.client.Response; 12 | import retrofit.http.GET; 13 | import rx.Observable; 14 | import rx.Observer; 15 | 16 | import static org.assertj.core.api.Assertions.assertThat; 17 | import static org.assertj.core.api.Assertions.failBecauseExceptionWasNotThrown; 18 | import static org.junit.Assert.fail; 19 | import static org.mockito.Matchers.any; 20 | import static org.mockito.Mockito.doReturn; 21 | import static org.mockito.Mockito.mock; 22 | 23 | public class ErrorHandlerTest { 24 | 25 | interface ExampleClient { 26 | @GET("/") 27 | Response throwsCustomException() throws TestException; 28 | 29 | @GET("/") 30 | void onErrorWrappedCustomException(Callback callback); 31 | 32 | @GET("/") 33 | Observable onErrorCustomException(); 34 | } 35 | 36 | static class TestException extends Exception { 37 | } 38 | 39 | /* An HTTP client which always returns a 400 response */ 40 | static class MockInvalidResponseClient implements Client { 41 | @Override public Response execute(Request request) throws IOException { 42 | return new Response("", 400, "invalid request", Collections.
emptyList(), null); 43 | } 44 | } 45 | 46 | ExampleClient client; 47 | ErrorHandler errorHandler; 48 | 49 | @Before public void setup() { 50 | errorHandler = mock(ErrorHandler.class); 51 | 52 | client = new RestAdapter.Builder() // 53 | .setEndpoint("http://example.com") 54 | .setClient(new MockInvalidResponseClient()) 55 | .setErrorHandler(errorHandler) 56 | .setExecutors(new Utils.SynchronousExecutor(), new Utils.SynchronousExecutor()) 57 | .build() 58 | .create(ExampleClient.class); 59 | } 60 | 61 | @Test public void customizedExceptionUsed() throws Throwable { 62 | TestException exception = new TestException(); 63 | doReturn(exception).when(errorHandler).handleError(any(RetrofitError.class)); 64 | 65 | try { 66 | client.throwsCustomException(); 67 | failBecauseExceptionWasNotThrown(TestException.class); 68 | } catch (TestException e) { 69 | assertThat(e).isSameAs(exception); 70 | } 71 | } 72 | 73 | @Test public void onErrorWrappedCustomException() throws Throwable { 74 | final TestException exception = new TestException(); 75 | doReturn(exception).when(errorHandler).handleError(any(RetrofitError.class)); 76 | 77 | client.onErrorWrappedCustomException(new Callback() { 78 | 79 | @Override public void success(Response response, Response response2) { 80 | failBecauseExceptionWasNotThrown(TestException.class); 81 | } 82 | 83 | @Override public void failure(RetrofitError error) { 84 | assertThat(error.getCause()).isSameAs(exception); 85 | } 86 | }); 87 | } 88 | 89 | @Test public void onErrorCustomException() throws Throwable { 90 | final TestException exception = new TestException(); 91 | doReturn(exception).when(errorHandler).handleError(any(RetrofitError.class)); 92 | 93 | client.onErrorCustomException().subscribe(new Observer() { 94 | @Override public void onCompleted() { 95 | failBecauseExceptionWasNotThrown(TestException.class); 96 | } 97 | 98 | @Override public void onError(Throwable e) { 99 | assertThat(e).isSameAs(exception); 100 | } 101 | 102 | @Override public void onNext(Response response) { 103 | failBecauseExceptionWasNotThrown(TestException.class); 104 | } 105 | }); 106 | } 107 | 108 | @Test public void returningNullThrowsException() throws Exception { 109 | doReturn(null).when(errorHandler).handleError(any(RetrofitError.class)); 110 | 111 | try { 112 | client.throwsCustomException(); 113 | fail(); 114 | } catch (IllegalStateException e) { 115 | assertThat(e.getMessage()).isEqualTo("Error handler returned null for wrapped exception."); 116 | } 117 | } 118 | } 119 | -------------------------------------------------------------------------------- /retrofit-converters/simplexml/src/test/java/retrofit/converter/SimpleXMLConverterTest.java: -------------------------------------------------------------------------------- 1 | package retrofit.converter; 2 | 3 | import static org.assertj.core.api.Assertions.assertThat; 4 | 5 | import java.io.ByteArrayOutputStream; 6 | 7 | import org.junit.Test; 8 | import org.simpleframework.xml.Default; 9 | import org.simpleframework.xml.DefaultType; 10 | import org.simpleframework.xml.Element; 11 | import org.simpleframework.xml.core.Persister; 12 | import org.simpleframework.xml.stream.Format; 13 | import org.simpleframework.xml.stream.HyphenStyle; 14 | import org.simpleframework.xml.stream.Verbosity; 15 | 16 | import retrofit.mime.TypedByteArray; 17 | import retrofit.mime.TypedInput; 18 | import retrofit.mime.TypedOutput; 19 | 20 | public class SimpleXMLConverterTest { 21 | private static final String MIME_TYPE = "application/xml; charset=UTF-8"; 22 | 23 | private final MyObject obj = new MyObject("hello world", 10); 24 | private final String objAsXML = String.format( 25 | "%s%d", 26 | obj.getMessage(), obj.getCount()); 27 | private final Converter converter = initConverter(); 28 | 29 | private static Converter initConverter() { 30 | Format format = new Format(0, null, new HyphenStyle(), Verbosity.HIGH); 31 | Persister persister = new Persister(format); 32 | return new SimpleXMLConverter(persister); 33 | } 34 | 35 | @Test 36 | public void serialize() throws Exception { 37 | final TypedOutput typedOutput = converter.toBody(obj); 38 | assertThat(typedOutput.mimeType()).isEqualTo(MIME_TYPE); 39 | assertThat(asString(typedOutput)).isEqualTo(objAsXML); 40 | } 41 | 42 | @Test 43 | public void deserialize() throws Exception { 44 | final TypedInput input = new TypedByteArray(MIME_TYPE, 45 | objAsXML.getBytes()); 46 | final MyObject result = (MyObject) converter.fromBody(input, 47 | MyObject.class); 48 | assertThat(result).isEqualTo(obj); 49 | } 50 | 51 | @Test(expected = ConversionException.class) 52 | public void deserializeWrongValue() throws Exception { 53 | final TypedInput input = new TypedByteArray(MIME_TYPE, 54 | "".getBytes()); 55 | converter.fromBody(input, MyObject.class); 56 | 57 | } 58 | 59 | @Test 60 | public void deserializeWrongClass() throws Exception { 61 | final TypedInput input = new TypedByteArray(MIME_TYPE, 62 | objAsXML.getBytes()); 63 | Object result = converter.fromBody(input, String.class); 64 | assertThat(result).isNull(); 65 | } 66 | 67 | private String asString(TypedOutput typedOutput) throws Exception { 68 | final ByteArrayOutputStream bytes = new ByteArrayOutputStream(); 69 | typedOutput.writeTo(bytes); 70 | return new String(bytes.toByteArray()); 71 | } 72 | 73 | @Default(value = DefaultType.FIELD) 74 | static class MyObject { 75 | @Element 76 | private String message; 77 | @Element 78 | private int count; 79 | 80 | public MyObject() { 81 | } 82 | 83 | public MyObject(String message, int count) { 84 | this.message = message; 85 | this.count = count; 86 | } 87 | 88 | public void setMessage(String message) { 89 | this.message = message; 90 | } 91 | 92 | public String getMessage() { 93 | return message; 94 | } 95 | 96 | public void setCount(int count) { 97 | this.count = count; 98 | } 99 | 100 | public int getCount() { 101 | return count; 102 | } 103 | 104 | @Override 105 | public int hashCode() { 106 | final int prime = 31; 107 | int result = 1; 108 | result = prime * result + count; 109 | result = prime * result 110 | + ((message == null) ? 0 : message.hashCode()); 111 | return result; 112 | } 113 | 114 | @Override 115 | public boolean equals(Object obj) { 116 | if (this == obj) { 117 | return true; 118 | } 119 | if (obj == null) { 120 | return false; 121 | } 122 | if (getClass() != obj.getClass()) { 123 | return false; 124 | } 125 | MyObject other = (MyObject) obj; 126 | if (count != other.count) { 127 | return false; 128 | } 129 | if (message == null) { 130 | if (other.message != null) { 131 | return false; 132 | } 133 | } else if (!message.equals(other.message)) { 134 | return false; 135 | } 136 | return true; 137 | } 138 | } 139 | } 140 | -------------------------------------------------------------------------------- /retrofit/src/main/java/retrofit/Utils.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2012 Square, Inc. 3 | * Copyright (C) 2007 The Guava Authors 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package retrofit; 18 | 19 | import java.io.ByteArrayOutputStream; 20 | import java.io.IOException; 21 | import java.io.InputStream; 22 | import java.util.concurrent.Executor; 23 | import retrofit.client.Request; 24 | import retrofit.client.Response; 25 | import retrofit.mime.TypedByteArray; 26 | import retrofit.mime.TypedInput; 27 | import retrofit.mime.TypedOutput; 28 | 29 | final class Utils { 30 | private static final int BUFFER_SIZE = 0x1000; 31 | 32 | /** 33 | * Creates a {@code byte[]} from reading the entirety of an {@link InputStream}. May return an 34 | * empty array but never {@code null}. 35 | *

36 | * Copied from Guava's {@code ByteStreams} class. 37 | */ 38 | static byte[] streamToBytes(InputStream stream) throws IOException { 39 | ByteArrayOutputStream baos = new ByteArrayOutputStream(); 40 | if (stream != null) { 41 | byte[] buf = new byte[BUFFER_SIZE]; 42 | int r; 43 | while ((r = stream.read(buf)) != -1) { 44 | baos.write(buf, 0, r); 45 | } 46 | } 47 | return baos.toByteArray(); 48 | } 49 | 50 | /** 51 | * Conditionally replace a {@link Request} with an identical copy whose body is backed by a 52 | * byte[] rather than an input stream. 53 | */ 54 | static Request readBodyToBytesIfNecessary(Request request) throws IOException { 55 | TypedOutput body = request.getBody(); 56 | if (body == null || body instanceof TypedByteArray) { 57 | return request; 58 | } 59 | 60 | String bodyMime = body.mimeType(); 61 | ByteArrayOutputStream baos = new ByteArrayOutputStream(); 62 | body.writeTo(baos); 63 | body = new TypedByteArray(bodyMime, baos.toByteArray()); 64 | 65 | return new Request(request.getMethod(), request.getUrl(), request.getHeaders(), body); 66 | } 67 | 68 | /** 69 | * Conditionally replace a {@link Response} with an identical copy whose body is backed by a 70 | * byte[] rather than an input stream. 71 | */ 72 | static Response readBodyToBytesIfNecessary(Response response) throws IOException { 73 | TypedInput body = response.getBody(); 74 | if (body == null || body instanceof TypedByteArray) { 75 | return response; 76 | } 77 | 78 | String bodyMime = body.mimeType(); 79 | InputStream is = body.in(); 80 | try { 81 | byte[] bodyBytes = Utils.streamToBytes(is); 82 | body = new TypedByteArray(bodyMime, bodyBytes); 83 | 84 | return replaceResponseBody(response, body); 85 | } finally { 86 | if (is != null) { 87 | try { 88 | is.close(); 89 | } catch (IOException ignored) { 90 | } 91 | } 92 | } 93 | } 94 | 95 | static Response replaceResponseBody(Response response, TypedInput body) { 96 | return new Response(response.getUrl(), response.getStatus(), response.getReason(), 97 | response.getHeaders(), body); 98 | } 99 | 100 | static void validateServiceClass(Class service) { 101 | if (!service.isInterface()) { 102 | throw new IllegalArgumentException("Only interface endpoint definitions are supported."); 103 | } 104 | // Prevent API interfaces from extending other interfaces. This not only avoids a bug in 105 | // Android (http://b.android.com/58753) but it forces composition of API declarations which is 106 | // the recommended pattern. 107 | if (service.getInterfaces().length > 0) { 108 | throw new IllegalArgumentException("Interface definitions must not extend other interfaces."); 109 | } 110 | } 111 | 112 | static class SynchronousExecutor implements Executor { 113 | @Override public void execute(Runnable runnable) { 114 | runnable.run(); 115 | } 116 | } 117 | 118 | private Utils() { 119 | // No instances. 120 | } 121 | } 122 | -------------------------------------------------------------------------------- /retrofit/src/main/java/retrofit/client/UrlConnectionClient.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2013 Square, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package retrofit.client; 17 | 18 | import java.io.IOException; 19 | import java.io.InputStream; 20 | import java.net.HttpURLConnection; 21 | import java.net.URL; 22 | import java.util.ArrayList; 23 | import java.util.List; 24 | import java.util.Map; 25 | import retrofit.mime.TypedInput; 26 | import retrofit.mime.TypedOutput; 27 | 28 | /** Retrofit client that uses {@link HttpURLConnection} for communication. */ 29 | public class UrlConnectionClient implements Client { 30 | private static final int CHUNK_SIZE = 4096; 31 | 32 | public UrlConnectionClient() { 33 | } 34 | 35 | @Override public Response execute(Request request) throws IOException { 36 | HttpURLConnection connection = openConnection(request); 37 | prepareRequest(connection, request); 38 | return readResponse(connection); 39 | } 40 | 41 | protected HttpURLConnection openConnection(Request request) throws IOException { 42 | HttpURLConnection connection = 43 | (HttpURLConnection) new URL(request.getUrl()).openConnection(); 44 | connection.setConnectTimeout(Defaults.CONNECT_TIMEOUT_MILLIS); 45 | connection.setReadTimeout(Defaults.READ_TIMEOUT_MILLIS); 46 | return connection; 47 | } 48 | 49 | void prepareRequest(HttpURLConnection connection, Request request) throws IOException { 50 | connection.setRequestMethod(request.getMethod()); 51 | connection.setDoInput(true); 52 | 53 | for (Header header : request.getHeaders()) { 54 | connection.addRequestProperty(header.getName(), header.getValue()); 55 | } 56 | 57 | TypedOutput body = request.getBody(); 58 | if (body != null) { 59 | connection.setDoOutput(true); 60 | connection.addRequestProperty("Content-Type", body.mimeType()); 61 | long length = body.length(); 62 | if (length != -1) { 63 | connection.setFixedLengthStreamingMode((int) length); 64 | connection.addRequestProperty("Content-Length", String.valueOf(length)); 65 | } else { 66 | connection.setChunkedStreamingMode(CHUNK_SIZE); 67 | } 68 | body.writeTo(connection.getOutputStream()); 69 | } 70 | } 71 | 72 | Response readResponse(HttpURLConnection connection) throws IOException { 73 | int status = connection.getResponseCode(); 74 | String reason = connection.getResponseMessage(); 75 | if (reason == null) reason = ""; // HttpURLConnection treats empty reason as null. 76 | 77 | List

headers = new ArrayList
(); 78 | for (Map.Entry> field : connection.getHeaderFields().entrySet()) { 79 | String name = field.getKey(); 80 | for (String value : field.getValue()) { 81 | headers.add(new Header(name, value)); 82 | } 83 | } 84 | 85 | String mimeType = connection.getContentType(); 86 | int length = connection.getContentLength(); 87 | InputStream stream; 88 | if (status >= 400) { 89 | stream = connection.getErrorStream(); 90 | } else { 91 | stream = connection.getInputStream(); 92 | } 93 | TypedInput responseBody = new TypedInputStream(mimeType, length, stream); 94 | return new Response(connection.getURL().toString(), status, reason, headers, responseBody); 95 | } 96 | 97 | private static class TypedInputStream implements TypedInput { 98 | private final String mimeType; 99 | private final long length; 100 | private final InputStream stream; 101 | 102 | private TypedInputStream(String mimeType, long length, InputStream stream) { 103 | this.mimeType = mimeType; 104 | this.length = length; 105 | this.stream = stream; 106 | } 107 | 108 | @Override public String mimeType() { 109 | return mimeType; 110 | } 111 | 112 | @Override public long length() { 113 | return length; 114 | } 115 | 116 | @Override public InputStream in() throws IOException { 117 | return stream; 118 | } 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /retrofit-mock/src/main/java/retrofit/MockHttpException.java: -------------------------------------------------------------------------------- 1 | // Copyright 2013 Square, Inc. 2 | package retrofit; 3 | 4 | import java.util.ArrayList; 5 | import java.util.List; 6 | import retrofit.client.Header; 7 | import retrofit.client.Response; 8 | import retrofit.converter.Converter; 9 | 10 | import static java.net.HttpURLConnection.HTTP_BAD_REQUEST; 11 | import static java.net.HttpURLConnection.HTTP_FORBIDDEN; 12 | import static java.net.HttpURLConnection.HTTP_INTERNAL_ERROR; 13 | import static java.net.HttpURLConnection.HTTP_MOVED_PERM; 14 | import static java.net.HttpURLConnection.HTTP_MOVED_TEMP; 15 | import static java.net.HttpURLConnection.HTTP_NOT_FOUND; 16 | import static java.net.HttpURLConnection.HTTP_UNAUTHORIZED; 17 | 18 | /** 19 | * An exception used to trigger the simulation of an HTTP error for mock services. 20 | * 21 | * @see MockRestAdapter 22 | */ 23 | public class MockHttpException extends RuntimeException { 24 | /** Create a new {@link MockHttpException} for HTTP 301 Moved Permanently. */ 25 | public static MockHttpException newMovedPermanentely(String location, Object responseBody) { 26 | if (location == null || "".equals(location.trim())) { 27 | throw new IllegalArgumentException("Location must not be blank."); 28 | } 29 | return new MockHttpException(HTTP_MOVED_PERM, "Moved Permanently", responseBody) 30 | .withHeader("Location", location); 31 | } 32 | 33 | /** Create a new {@link MockHttpException} for HTTP 302 Moved Temporarily. */ 34 | public static MockHttpException newMovedTemporarily(String location, Object responseBody) { 35 | if (location == null || "".equals(location.trim())) { 36 | throw new IllegalArgumentException("Location must not be blank."); 37 | } 38 | return new MockHttpException(HTTP_MOVED_TEMP, "Moved Temporarily", responseBody) 39 | .withHeader("Location", location); 40 | } 41 | 42 | /** Create a new {@link MockHttpException} for HTTP 400 Bad Request. */ 43 | public static MockHttpException newBadRequest(Object responseBody) { 44 | return new MockHttpException(HTTP_BAD_REQUEST, "Bad Request", responseBody); 45 | } 46 | 47 | /** Create a new {@link MockHttpException} for HTTP 401 Unauthorized. */ 48 | public static MockHttpException newUnauthorized(Object responseBody) { 49 | return new MockHttpException(HTTP_UNAUTHORIZED, "Unauthorized", responseBody); 50 | } 51 | 52 | /** Create a new {@link MockHttpException} for HTTP 403 Forbidden. */ 53 | public static MockHttpException newForbidden(Object responseBody) { 54 | return new MockHttpException(HTTP_FORBIDDEN, "Forbidded", responseBody); 55 | } 56 | 57 | /** Create a new {@link MockHttpException} for HTTP 404 Not Found. */ 58 | public static MockHttpException newNotFound(Object responseBody) { 59 | return new MockHttpException(HTTP_NOT_FOUND, "Not Found", responseBody); 60 | } 61 | 62 | /** Create a new {@link MockHttpException} for HTTP 500 Internal Server Error. */ 63 | public static MockHttpException newInternalError(Object responseBody) { 64 | return new MockHttpException(HTTP_INTERNAL_ERROR, "Internal Server Error", responseBody); 65 | } 66 | 67 | final int code; 68 | final String reason; 69 | final Object responseBody; 70 | final List
headers = new ArrayList
(2); 71 | 72 | /** 73 | * Create a new HTTP exception. 74 | * 75 | * @param code HTTP status code to trigger. Must be 300 or higher. 76 | * @param reason HTTP status reason message. 77 | * @param responseBody Object to use as the contents of the response body. 78 | */ 79 | public MockHttpException(int code, String reason, Object responseBody) { 80 | super("HTTP " + code + " " + reason); 81 | if (code < 300 || code > 599) { 82 | throw new IllegalArgumentException("Unsupported HTTP error code: " + code); 83 | } 84 | if (reason == null || "".equals(reason.trim())) { 85 | throw new IllegalArgumentException("Reason must not be blank."); 86 | } 87 | this.code = code; 88 | this.reason = reason; 89 | this.responseBody = responseBody; 90 | } 91 | 92 | /** Add a header to the response. */ 93 | public MockHttpException withHeader(String name, String value) { 94 | if (name == null || "".equals(name.trim())) { 95 | throw new IllegalArgumentException("Header name must not be blank."); 96 | } 97 | if (value == null || "".equals(value.trim())) { 98 | throw new IllegalArgumentException("Header value must not be blank."); 99 | } 100 | headers.add(new Header(name, value)); 101 | return this; 102 | } 103 | 104 | Response toResponse(Converter converter) { 105 | return new Response("", code, reason, headers, new MockTypedInput(converter, responseBody)); 106 | } 107 | } 108 | --------------------------------------------------------------------------------