Browse Source
* Add Moshi * Update README.md --------- Co-authored-by: Vikramaditya Chhapwale <cvikramad@gmail.com>pull/2185/head
Vik
1 year ago
committed by
GitHub
13 changed files with 707 additions and 0 deletions
@ -0,0 +1,13 @@ |
|||||||
|
Moshi Codec |
||||||
|
=================== |
||||||
|
|
||||||
|
This module adds support for encoding and decoding JSON via the Moshi library. |
||||||
|
|
||||||
|
Add `MoshiEncoder` and/or `MoshiDecoder` to your `Feign.Builder` like so: |
||||||
|
|
||||||
|
```java |
||||||
|
GitHub github = Feign.builder() |
||||||
|
.encoder(new MoshiEncoder()) |
||||||
|
.decoder(new MoshiDecoder()) |
||||||
|
.target(GitHub.class, "https://api.github.com"); |
||||||
|
``` |
@ -0,0 +1,58 @@ |
|||||||
|
<?xml version="1.0" encoding="UTF-8"?> |
||||||
|
<!-- |
||||||
|
|
||||||
|
Copyright 2012-2023 The Feign Authors |
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except |
||||||
|
in compliance with the License. You may obtain a copy of the License at |
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0 |
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software distributed under the License |
||||||
|
is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express |
||||||
|
or implied. See the License for the specific language governing permissions and limitations under |
||||||
|
the License. |
||||||
|
|
||||||
|
--> |
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> |
||||||
|
<modelVersion>4.0.0</modelVersion> |
||||||
|
|
||||||
|
<parent> |
||||||
|
<groupId>io.github.openfeign</groupId> |
||||||
|
<artifactId>parent</artifactId> |
||||||
|
<version>13.0-SNAPSHOT</version> |
||||||
|
</parent> |
||||||
|
|
||||||
|
<artifactId>feign-moshi</artifactId> |
||||||
|
<name>Feign Moshi</name> |
||||||
|
<description>Feign Moshi</description> |
||||||
|
|
||||||
|
<properties> |
||||||
|
<main.basedir>${project.basedir}/..</main.basedir> |
||||||
|
</properties> |
||||||
|
|
||||||
|
<dependencies> |
||||||
|
<dependency> |
||||||
|
<groupId>${project.groupId}</groupId> |
||||||
|
<artifactId>feign-core</artifactId> |
||||||
|
</dependency> |
||||||
|
|
||||||
|
<dependency> |
||||||
|
<groupId>com.squareup.moshi</groupId> |
||||||
|
<artifactId>moshi</artifactId> |
||||||
|
</dependency> |
||||||
|
|
||||||
|
<dependency> |
||||||
|
<groupId>com.google.guava</groupId> |
||||||
|
<artifactId>guava</artifactId> |
||||||
|
<version>${guava.version}</version> |
||||||
|
</dependency> |
||||||
|
|
||||||
|
<dependency> |
||||||
|
<groupId>${project.groupId}</groupId> |
||||||
|
<artifactId>feign-core</artifactId> |
||||||
|
<type>test-jar</type> |
||||||
|
<scope>test</scope> |
||||||
|
</dependency> |
||||||
|
</dependencies> |
||||||
|
</project> |
@ -0,0 +1,74 @@ |
|||||||
|
/* |
||||||
|
* Copyright 2012-2023 The Feign Authors |
||||||
|
* |
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except |
||||||
|
* in compliance with the License. You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software distributed under the License |
||||||
|
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express |
||||||
|
* or implied. See the License for the specific language governing permissions and limitations under |
||||||
|
* the License. |
||||||
|
*/ |
||||||
|
package feign.moshi; |
||||||
|
|
||||||
|
import com.google.common.io.CharStreams; |
||||||
|
import com.squareup.moshi.JsonAdapter; |
||||||
|
import com.squareup.moshi.JsonDataException; |
||||||
|
import com.squareup.moshi.JsonEncodingException; |
||||||
|
import com.squareup.moshi.Moshi; |
||||||
|
import feign.Response; |
||||||
|
import feign.Util; |
||||||
|
import feign.codec.Decoder; |
||||||
|
import java.io.IOException; |
||||||
|
import java.io.Reader; |
||||||
|
import java.lang.reflect.Type; |
||||||
|
import static feign.Util.UTF_8; |
||||||
|
import static feign.Util.ensureClosed; |
||||||
|
|
||||||
|
public class MoshiDecoder implements Decoder { |
||||||
|
private final Moshi moshi; |
||||||
|
|
||||||
|
public MoshiDecoder(Moshi moshi) { |
||||||
|
this.moshi = moshi; |
||||||
|
} |
||||||
|
|
||||||
|
public MoshiDecoder() { |
||||||
|
this.moshi = new Moshi.Builder().build(); |
||||||
|
} |
||||||
|
|
||||||
|
public MoshiDecoder(Iterable<JsonAdapter<?>> adapters) { |
||||||
|
this(MoshiFactory.create(adapters)); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
@Override |
||||||
|
public Object decode(Response response, Type type) throws IOException { |
||||||
|
JsonAdapter<Object> jsonAdapter = moshi.adapter(type); |
||||||
|
|
||||||
|
if (response.status() == 404 || response.status() == 204) |
||||||
|
return Util.emptyValueOf(type); |
||||||
|
if (response.body() == null) |
||||||
|
return null; |
||||||
|
|
||||||
|
Reader reader = response.body().asReader(UTF_8); |
||||||
|
|
||||||
|
try { |
||||||
|
return parseJson(jsonAdapter, reader); |
||||||
|
} catch (JsonDataException e) { |
||||||
|
if (e.getCause() != null && e.getCause() instanceof IOException) { |
||||||
|
throw (IOException) e.getCause(); |
||||||
|
} |
||||||
|
throw e; |
||||||
|
} finally { |
||||||
|
ensureClosed(reader); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private Object parseJson(JsonAdapter<Object> jsonAdapter, Reader reader) throws IOException { |
||||||
|
String targetString = CharStreams.toString(reader); |
||||||
|
return jsonAdapter.fromJson(targetString); |
||||||
|
} |
||||||
|
} |
||||||
|
|
@ -0,0 +1,44 @@ |
|||||||
|
/* |
||||||
|
* Copyright 2012-2023 The Feign Authors |
||||||
|
* |
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except |
||||||
|
* in compliance with the License. You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software distributed under the License |
||||||
|
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express |
||||||
|
* or implied. See the License for the specific language governing permissions and limitations under |
||||||
|
* the License. |
||||||
|
*/ |
||||||
|
package feign.moshi; |
||||||
|
|
||||||
|
import com.squareup.moshi.JsonAdapter; |
||||||
|
import com.squareup.moshi.Moshi; |
||||||
|
import feign.RequestTemplate; |
||||||
|
import feign.codec.Encoder; |
||||||
|
import java.lang.reflect.Type; |
||||||
|
import java.util.Collections; |
||||||
|
|
||||||
|
public class MoshiEncoder implements Encoder { |
||||||
|
|
||||||
|
private final Moshi moshi; |
||||||
|
|
||||||
|
public MoshiEncoder() { |
||||||
|
this.moshi = new Moshi.Builder().build(); |
||||||
|
} |
||||||
|
|
||||||
|
public MoshiEncoder(Moshi moshi) { |
||||||
|
this.moshi = moshi; |
||||||
|
} |
||||||
|
|
||||||
|
public MoshiEncoder(Iterable<JsonAdapter<?>> adapters) { |
||||||
|
this(MoshiFactory.create(adapters)); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void encode(Object object, Type bodyType, RequestTemplate template) { |
||||||
|
JsonAdapter<Object> jsonAdapter = moshi.adapter(bodyType).indent(" "); |
||||||
|
template.body(jsonAdapter.toJson(object)); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,36 @@ |
|||||||
|
/* |
||||||
|
* Copyright 2012-2023 The Feign Authors |
||||||
|
* |
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except |
||||||
|
* in compliance with the License. You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software distributed under the License |
||||||
|
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express |
||||||
|
* or implied. See the License for the specific language governing permissions and limitations under |
||||||
|
* the License. |
||||||
|
*/ |
||||||
|
package feign.moshi; |
||||||
|
|
||||||
|
import com.squareup.moshi.JsonAdapter; |
||||||
|
import com.squareup.moshi.Moshi; |
||||||
|
|
||||||
|
public class MoshiFactory { |
||||||
|
private MoshiFactory() {} |
||||||
|
|
||||||
|
/** |
||||||
|
* Registers JsonAdapter by implicit type. Adds one to read numbers in a {@code Map<String, |
||||||
|
* Object>} as Integers. |
||||||
|
*/ |
||||||
|
static Moshi create(Iterable<JsonAdapter<?>> adapters) { |
||||||
|
Moshi.Builder builder = new Moshi.Builder(); |
||||||
|
|
||||||
|
for (JsonAdapter<?> adapter : adapters) { |
||||||
|
builder.add(adapter.getClass(), adapter); |
||||||
|
} |
||||||
|
|
||||||
|
return builder.build(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
@ -0,0 +1,176 @@ |
|||||||
|
/* |
||||||
|
* Copyright 2012-2023 The Feign Authors |
||||||
|
* |
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except |
||||||
|
* in compliance with the License. You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software distributed under the License |
||||||
|
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express |
||||||
|
* or implied. See the License for the specific language governing permissions and limitations under |
||||||
|
* the License. |
||||||
|
*/ |
||||||
|
package feign.moshi; |
||||||
|
|
||||||
|
import com.squareup.moshi.JsonAdapter; |
||||||
|
import com.squareup.moshi.Moshi; |
||||||
|
import feign.Request; |
||||||
|
import feign.Response; |
||||||
|
import feign.Util; |
||||||
|
import org.junit.Test; |
||||||
|
import java.util.Collections; |
||||||
|
import java.util.LinkedHashMap; |
||||||
|
import java.util.LinkedList; |
||||||
|
import java.util.List; |
||||||
|
import static feign.Util.UTF_8; |
||||||
|
import static feign.assertj.FeignAssertions.assertThat; |
||||||
|
import static org.junit.Assert.assertEquals; |
||||||
|
import static org.junit.Assert.assertNull; |
||||||
|
|
||||||
|
public class MoshiDecoderTest { |
||||||
|
|
||||||
|
@Test |
||||||
|
public void decodes() throws Exception { |
||||||
|
|
||||||
|
class Zone extends LinkedHashMap<String, Object> { |
||||||
|
|
||||||
|
Zone(String name) { |
||||||
|
this(name, null); |
||||||
|
} |
||||||
|
|
||||||
|
Zone(String name, String id) { |
||||||
|
put("name", name); |
||||||
|
if (id != null) { |
||||||
|
put("id", id); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L; |
||||||
|
} |
||||||
|
|
||||||
|
List<Zone> zones = new LinkedList<>(); |
||||||
|
zones.add(new Zone("denominator.io.")); |
||||||
|
zones.add(new Zone("denominator.io.", "ABCD")); |
||||||
|
|
||||||
|
Response response = Response.builder() |
||||||
|
.status(200) |
||||||
|
.reason("OK") |
||||||
|
.headers(Collections.emptyMap()) |
||||||
|
.request(Request.create(Request.HttpMethod.GET, "/api", Collections.emptyMap(), null, |
||||||
|
Util.UTF_8)) |
||||||
|
.body(zonesJson, UTF_8) |
||||||
|
.build(); |
||||||
|
|
||||||
|
assertEquals(zones, |
||||||
|
new MoshiDecoder().decode(response, List.class)); |
||||||
|
} |
||||||
|
|
||||||
|
private String zonesJson = ""//
|
||||||
|
+ "[\n"//
|
||||||
|
+ " {\n"//
|
||||||
|
+ " \"name\": \"denominator.io.\"\n"//
|
||||||
|
+ " },\n"//
|
||||||
|
+ " {\n"//
|
||||||
|
+ " \"name\": \"denominator.io.\",\n"//
|
||||||
|
+ " \"id\": \"ABCD\"\n"//
|
||||||
|
+ " }\n"//
|
||||||
|
+ "]\n"; |
||||||
|
|
||||||
|
private final String videoGamesJson = "{\n " + |
||||||
|
" \"hero\": {\n " + |
||||||
|
" \"enemy\": \"Bowser\",\n " + |
||||||
|
" \"name\": \"Luigi\"\n " + |
||||||
|
"},\n " + |
||||||
|
"\"name\": \"Super Mario\"\n " + |
||||||
|
"}"; |
||||||
|
|
||||||
|
@Test |
||||||
|
public void nullBodyDecodesToNull() throws Exception { |
||||||
|
Response response = Response.builder() |
||||||
|
.status(204) |
||||||
|
.reason("OK") |
||||||
|
.headers(Collections.emptyMap()) |
||||||
|
.request(Request.create(Request.HttpMethod.GET, "/api", Collections.emptyMap(), null, |
||||||
|
Util.UTF_8)) |
||||||
|
.build(); |
||||||
|
assertNull(new MoshiDecoder().decode(response, String.class)); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void emptyBodyDecodesToNull() throws Exception { |
||||||
|
Response response = Response.builder() |
||||||
|
.status(204) |
||||||
|
.reason("OK") |
||||||
|
.headers(Collections.emptyMap()) |
||||||
|
.request(Request.create(Request.HttpMethod.GET, "/api", Collections.emptyMap(), null, |
||||||
|
Util.UTF_8)) |
||||||
|
.body(new byte[0]) |
||||||
|
.build(); |
||||||
|
assertNull(new MoshiDecoder().decode(response, String.class)); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
/** Enabled via {@link feign.Feign.Builder#dismiss404()} */ |
||||||
|
@Test |
||||||
|
public void notFoundDecodesToEmpty() throws Exception { |
||||||
|
Response response = Response.builder() |
||||||
|
.status(404) |
||||||
|
.reason("NOT FOUND") |
||||||
|
.headers(Collections.emptyMap()) |
||||||
|
.request(Request.create(Request.HttpMethod.GET, "/api", Collections.emptyMap(), null, |
||||||
|
Util.UTF_8)) |
||||||
|
.build(); |
||||||
|
assertThat((byte[]) new MoshiDecoder().decode(response, byte[].class)).isEmpty(); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void customDecoder() throws Exception { |
||||||
|
final UpperZoneJSONAdapter upperZoneAdapter = new UpperZoneJSONAdapter(); |
||||||
|
|
||||||
|
MoshiDecoder decoder = new MoshiDecoder(Collections.singleton(upperZoneAdapter)); |
||||||
|
|
||||||
|
List<Zone> zones = new LinkedList<>(); |
||||||
|
zones.add(new Zone("DENOMINATOR.IO.")); |
||||||
|
zones.add(new Zone("DENOMINATOR.IO.", "ABCD")); |
||||||
|
|
||||||
|
Response response = |
||||||
|
Response.builder() |
||||||
|
.status(200) |
||||||
|
.reason("OK") |
||||||
|
.headers(Collections.emptyMap()) |
||||||
|
.request( |
||||||
|
Request.create(Request.HttpMethod.GET, "/api", Collections.emptyMap(), null, |
||||||
|
Util.UTF_8)) |
||||||
|
.body(zonesJson, UTF_8) |
||||||
|
.build(); |
||||||
|
|
||||||
|
assertEquals(zones, decoder.decode(response, UpperZoneJSONAdapter.class)); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void customObjectDecoder() throws Exception { |
||||||
|
final JsonAdapter<VideoGame> videoGameJsonAdapter = |
||||||
|
new Moshi.Builder().build().adapter(VideoGame.class); |
||||||
|
|
||||||
|
MoshiDecoder decoder = new MoshiDecoder(Collections.singleton(videoGameJsonAdapter)); |
||||||
|
|
||||||
|
VideoGame videoGame = new VideoGame("Super Mario", "Luigi", "Bowser"); |
||||||
|
|
||||||
|
Response response = |
||||||
|
Response.builder() |
||||||
|
.status(200) |
||||||
|
.reason("OK") |
||||||
|
.headers(Collections.emptyMap()) |
||||||
|
.request( |
||||||
|
Request.create(Request.HttpMethod.GET, "/api", Collections.emptyMap(), null, |
||||||
|
Util.UTF_8)) |
||||||
|
.body(videoGamesJson, UTF_8) |
||||||
|
.build(); |
||||||
|
|
||||||
|
VideoGame actual = (VideoGame) decoder.decode(response, videoGameJsonAdapter.getClass()); |
||||||
|
|
||||||
|
assertThat(actual) |
||||||
|
.isEqualToComparingFieldByFieldRecursively(videoGame); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,105 @@ |
|||||||
|
/* |
||||||
|
* Copyright 2012-2023 The Feign Authors |
||||||
|
* |
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except |
||||||
|
* in compliance with the License. You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software distributed under the License |
||||||
|
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express |
||||||
|
* or implied. See the License for the specific language governing permissions and limitations under |
||||||
|
* the License. |
||||||
|
*/ |
||||||
|
package feign.moshi; |
||||||
|
|
||||||
|
import com.squareup.moshi.JsonAdapter; |
||||||
|
import com.squareup.moshi.Moshi; |
||||||
|
import feign.RequestTemplate; |
||||||
|
import org.junit.Test; |
||||||
|
import java.util.*; |
||||||
|
import static feign.assertj.FeignAssertions.assertThat; |
||||||
|
|
||||||
|
public class MoshiEncoderTest { |
||||||
|
|
||||||
|
@Test |
||||||
|
public void encodesMapObjectNumericalValuesAsInteger() { |
||||||
|
Map<String, Object> map = new LinkedHashMap<>(); |
||||||
|
map.put("foo", 1); |
||||||
|
|
||||||
|
RequestTemplate template = new RequestTemplate(); |
||||||
|
new MoshiEncoder().encode(map, Map.class, template); |
||||||
|
|
||||||
|
assertThat(template).hasBody("{\n" //
|
||||||
|
+ " \"foo\": 1\n" //
|
||||||
|
+ "}"); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void encodesFormParams() { |
||||||
|
|
||||||
|
Map<String, Object> form = new LinkedHashMap<>(); |
||||||
|
form.put("foo", 1); |
||||||
|
form.put("bar", Arrays.asList(2, 3)); |
||||||
|
|
||||||
|
RequestTemplate template = new RequestTemplate(); |
||||||
|
|
||||||
|
new MoshiEncoder().encode(form, Map.class, template); |
||||||
|
|
||||||
|
assertThat(template).hasBody("{\n" //
|
||||||
|
+ " \"foo\": 1,\n" //
|
||||||
|
+ " \"bar\": [\n" //
|
||||||
|
+ " 2,\n" //
|
||||||
|
+ " 3\n" //
|
||||||
|
+ " ]\n" //
|
||||||
|
+ "}"); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void customEncoder() { |
||||||
|
final UpperZoneJSONAdapter upperZoneAdapter = new UpperZoneJSONAdapter(); |
||||||
|
|
||||||
|
MoshiEncoder encoder = new MoshiEncoder(Collections.singleton(upperZoneAdapter)); |
||||||
|
|
||||||
|
List<Zone> zones = new LinkedList<>(); |
||||||
|
zones.add(new Zone("denominator.io.")); |
||||||
|
zones.add(new Zone("denominator.io.", "abcd")); |
||||||
|
|
||||||
|
RequestTemplate template = new RequestTemplate(); |
||||||
|
encoder.encode(zones, UpperZoneJSONAdapter.class, template); |
||||||
|
|
||||||
|
assertThat(template).hasBody("" //
|
||||||
|
+ "[\n" //
|
||||||
|
+ " {\n" //
|
||||||
|
+ " \"name\": \"DENOMINATOR.IO.\"\n" //
|
||||||
|
+ " },\n" //
|
||||||
|
+ " {\n" //
|
||||||
|
+ " \"name\": \"DENOMINATOR.IO.\",\n" //
|
||||||
|
+ " \"id\": \"ABCD\"\n" //
|
||||||
|
+ " }\n" //
|
||||||
|
+ "]"); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void customObjectEncoder() { |
||||||
|
final JsonAdapter<VideoGame> videoGameJsonAdapter = |
||||||
|
new Moshi.Builder().build().adapter(VideoGame.class); |
||||||
|
MoshiEncoder encoder = new MoshiEncoder(Collections.singleton(videoGameJsonAdapter)); |
||||||
|
|
||||||
|
VideoGame videoGame = new VideoGame("Super Mario", "Luigi", "Bowser"); |
||||||
|
|
||||||
|
RequestTemplate template = new RequestTemplate(); |
||||||
|
encoder.encode(videoGame, videoGameJsonAdapter.getClass(), template); |
||||||
|
|
||||||
|
|
||||||
|
assertThat(template) |
||||||
|
.hasBody("{\n" + |
||||||
|
" \"hero\": {\n" + |
||||||
|
" \"enemy\": \"Bowser\",\n" + |
||||||
|
" \"name\": \"Luigi\"\n" + |
||||||
|
" },\n" + |
||||||
|
" \"name\": \"Super Mario\"\n" + |
||||||
|
"}"); |
||||||
|
} |
||||||
|
} |
||||||
|
|
@ -0,0 +1,52 @@ |
|||||||
|
/* |
||||||
|
* Copyright 2012-2023 The Feign Authors |
||||||
|
* |
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except |
||||||
|
* in compliance with the License. You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software distributed under the License |
||||||
|
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express |
||||||
|
* or implied. See the License for the specific language governing permissions and limitations under |
||||||
|
* the License. |
||||||
|
*/ |
||||||
|
package feign.moshi; |
||||||
|
|
||||||
|
import com.squareup.moshi.*; |
||||||
|
import java.io.IOException; |
||||||
|
import java.util.LinkedList; |
||||||
|
import java.util.Map; |
||||||
|
|
||||||
|
class UpperZoneJSONAdapter extends JsonAdapter<LinkedList<Zone>> { |
||||||
|
|
||||||
|
@ToJson |
||||||
|
public void toJson(JsonWriter out, LinkedList<Zone> value) throws IOException { |
||||||
|
out.beginArray(); |
||||||
|
for (Zone zone : value) { |
||||||
|
out.beginObject(); |
||||||
|
for (Map.Entry<String, Object> entry : zone.entrySet()) { |
||||||
|
out.name(entry.getKey()).value(entry.getValue().toString().toUpperCase()); |
||||||
|
} |
||||||
|
out.endObject(); |
||||||
|
} |
||||||
|
out.endArray(); |
||||||
|
} |
||||||
|
|
||||||
|
@FromJson |
||||||
|
public LinkedList<Zone> fromJson(JsonReader in) throws IOException { |
||||||
|
LinkedList<Zone> zones = new LinkedList<>(); |
||||||
|
in.beginArray(); |
||||||
|
while (in.hasNext()) { |
||||||
|
in.beginObject(); |
||||||
|
Zone zone = new Zone(); |
||||||
|
while (in.hasNext()) { |
||||||
|
zone.put(in.nextName(), in.nextString().toUpperCase()); |
||||||
|
} |
||||||
|
in.endObject(); |
||||||
|
zones.add(zone); |
||||||
|
} |
||||||
|
in.endArray(); |
||||||
|
return zones; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,45 @@ |
|||||||
|
/* |
||||||
|
* Copyright 2012-2023 The Feign Authors |
||||||
|
* |
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except |
||||||
|
* in compliance with the License. You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software distributed under the License |
||||||
|
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express |
||||||
|
* or implied. See the License for the specific language governing permissions and limitations under |
||||||
|
* the License. |
||||||
|
*/ |
||||||
|
package feign.moshi; |
||||||
|
|
||||||
|
import com.squareup.moshi.Json; |
||||||
|
|
||||||
|
public class VideoGame { |
||||||
|
|
||||||
|
@Json(name = "name") |
||||||
|
public final String name; |
||||||
|
|
||||||
|
@Json(name = "hero") |
||||||
|
public final Hero hero; |
||||||
|
|
||||||
|
public VideoGame(String name, String hero, String enemy) { |
||||||
|
this.name = name; |
||||||
|
this.hero = new Hero(hero, enemy); |
||||||
|
} |
||||||
|
|
||||||
|
static class Hero { |
||||||
|
@Json(name = "name") |
||||||
|
public final String name; |
||||||
|
|
||||||
|
@Json(name = "enemy") |
||||||
|
public final String enemyName; |
||||||
|
|
||||||
|
Hero(String name, String enemyName) { |
||||||
|
this.name = name; |
||||||
|
this.enemyName = enemyName; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
} |
@ -0,0 +1,37 @@ |
|||||||
|
/* |
||||||
|
* Copyright 2012-2023 The Feign Authors |
||||||
|
* |
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except |
||||||
|
* in compliance with the License. You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software distributed under the License |
||||||
|
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express |
||||||
|
* or implied. See the License for the specific language governing permissions and limitations under |
||||||
|
* the License. |
||||||
|
*/ |
||||||
|
package feign.moshi; |
||||||
|
|
||||||
|
import java.util.LinkedHashMap; |
||||||
|
|
||||||
|
public class Zone extends LinkedHashMap<String, Object> { |
||||||
|
|
||||||
|
Zone() { |
||||||
|
// for reflective instantiation.
|
||||||
|
} |
||||||
|
|
||||||
|
Zone(String name) { |
||||||
|
this(name, null); |
||||||
|
} |
||||||
|
|
||||||
|
Zone(String name, String id) { |
||||||
|
put("name", name); |
||||||
|
if (id != null) { |
||||||
|
put("id", id); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L; |
||||||
|
} |
||||||
|
|
@ -0,0 +1,48 @@ |
|||||||
|
/* |
||||||
|
* Copyright 2012-2023 The Feign Authors |
||||||
|
* |
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except |
||||||
|
* in compliance with the License. You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software distributed under the License |
||||||
|
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express |
||||||
|
* or implied. See the License for the specific language governing permissions and limitations under |
||||||
|
* the License. |
||||||
|
*/ |
||||||
|
package feign.moshi.examples; |
||||||
|
|
||||||
|
import feign.Feign; |
||||||
|
import feign.Param; |
||||||
|
import feign.RequestLine; |
||||||
|
import feign.moshi.MoshiDecoder; |
||||||
|
import feign.moshi.MoshiEncoder; |
||||||
|
import java.util.List; |
||||||
|
|
||||||
|
public class GithubExample { |
||||||
|
|
||||||
|
public static void main(String... args) { |
||||||
|
GitHub github = Feign.builder().encoder(new MoshiEncoder()) |
||||||
|
.decoder(new MoshiDecoder()) |
||||||
|
.target(GitHub.class, "https://api.github.com"); |
||||||
|
|
||||||
|
System.out.println("Let's fetch and print a list of the contributors to this library."); |
||||||
|
List<Contributor> contributors = github.contributors("netflix", "feign"); |
||||||
|
for (Contributor contributor : contributors) { |
||||||
|
System.out.println(contributor.login + " (" + contributor.contributions + ")"); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
interface GitHub { |
||||||
|
|
||||||
|
@RequestLine("GET /repos/{owner}/{repo}/contributors") |
||||||
|
List<Contributor> contributors(@Param("owner") String owner, @Param("repo") String repo); |
||||||
|
} |
||||||
|
|
||||||
|
static class Contributor { |
||||||
|
|
||||||
|
String login; |
||||||
|
int contributions; |
||||||
|
} |
||||||
|
} |
Loading…
Reference in new issue