Browse Source

Rework the Jackson module as a Jackson Jr alternative (#1409)

Co-authored-by: Marvin Froeder <velo@users.noreply.github.com>
pull/1418/head
ashleyfrieze 4 years ago committed by GitHub
parent
commit
07850fce23
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 3
      README.md
  2. 43
      jackson-jr/README.md
  3. 58
      jackson-jr/pom.xml
  4. 107
      jackson-jr/src/main/java/feign/jackson/jr/JacksonJrDecoder.java
  5. 65
      jackson-jr/src/main/java/feign/jackson/jr/JacksonJrEncoder.java
  6. 49
      jackson-jr/src/main/java/feign/jackson/jr/JacksonJrMapper.java
  7. 285
      jackson-jr/src/test/java/feign/jackson/jr/JacksonCodecTest.java
  8. 74
      jackson-jr/src/test/java/feign/jackson/jr/JavaLocalDateExtension.java
  9. 58
      jackson-jr/src/test/java/feign/jackson/jr/examples/GitHubExample.java
  10. 13
      pom.xml
  11. 1
      src/docs/overview-mindmap.iuml

3
README.md

@ -360,6 +360,9 @@ public class Example {
} }
``` ```
For the lighter weight Jackson Jr, use `JacksonJrEncoder` and `JacksonJrDecoder` from
the [Jackson Jr Module](./jackson-jr).
### Sax ### Sax
[SaxDecoder](./sax) allows you to decode XML in a way that is compatible with normal JVM and also Android environments. [SaxDecoder](./sax) allows you to decode XML in a way that is compatible with normal JVM and also Android environments.

43
jackson-jr/README.md

@ -0,0 +1,43 @@
Jackson Jr Codec
===================
This module adds support for encoding and decoding JSON via Jackson Jr. This
is a significantly smaller and faster version of Jackson, which may be of benefit
in smaller runtime containers.
Add `JacksonJrEncoder` and/or `JacksonJrDecoder` to your `Feign.Builder` like so:
```java
GitHub github = Feign.builder()
.encoder(new JacksonJrEncoder())
.decoder(new JacksonJrDecoder())
.target(GitHub.class, "https://api.github.com");
```
If you want to customize the `JSON` object that is used, provide it to the `JacksonJrEncoder` and `JacksonJrDecoder`:
```java
JSON json = Json.builder()
.register(JacksonAnnotationExtension.builder()
.withVisibility(JsonAutoDetect.Value.defaultVisibility())
.build())
.build();
GitHub github = Feign.builder()
.encoder(new JacksonJrEncoder(json))
.decoder(new JacksonJrDecoder(json))
.target(GitHub.class, "https://api.github.com");
```
Customisation is also possible by passing `JacksonJrExtension` objects
into the constructor of the `JacksonJrEncoder` or `JacksonJrDecoder`:
```java
List<JacksonJrExtension> extensions = singletonList(JacksonAnnotationExtension.builder()
.withVisibility(JsonAutoDetect.Value.defaultVisibility())
.build());
GitHub github = Feign.builder()
.encoder(new JacksonJrEncoder(extensions))
.decoder(new JacksonJrDecoder(extensions))
.target(GitHub.class, "https://api.github.com");
```

58
jackson-jr/pom.xml

@ -0,0 +1,58 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright 2012-2021 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>11.3-SNAPSHOT</version>
</parent>
<artifactId>feign-jackson-jr</artifactId>
<name>Feign Jackson Jr</name>
<description>Feign Jackson Jr</description>
<properties>
<main.basedir>${project.basedir}/..</main.basedir>
</properties>
<dependencies>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>feign-core</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.jr</groupId>
<artifactId>jackson-jr-objects</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.jr</groupId>
<artifactId>jackson-jr-annotation-support</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>feign-core</artifactId>
<type>test-jar</type>
<scope>test</scope>
</dependency>
</dependencies>
</project>

107
jackson-jr/src/main/java/feign/jackson/jr/JacksonJrDecoder.java

@ -0,0 +1,107 @@
/**
* Copyright 2012-2021 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.jackson.jr;
import com.fasterxml.jackson.jr.ob.JSON;
import com.fasterxml.jackson.jr.ob.JSONObjectException;
import com.fasterxml.jackson.jr.ob.JacksonJrExtension;
import feign.Response;
import feign.codec.DecodeException;
import feign.codec.Decoder;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.Reader;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.List;
import java.util.Map;
/**
* A {@link Decoder} that uses Jackson Jr to convert objects to String or byte representation.
*/
public class JacksonJrDecoder extends JacksonJrMapper implements Decoder {
@FunctionalInterface
interface Transformer {
Object apply(JSON mapper, Reader reader) throws IOException;
}
public JacksonJrDecoder() {
super();
}
/**
* Construct with a custom {@link JSON} to use for decoding
*
* @param mapper the mapper to use
*/
public JacksonJrDecoder(JSON mapper) {
super(mapper);
}
/**
* Construct with a series of {@link JacksonJrExtension} objects that are registered into the
* {@link JSON}
*
* @param iterable the source of the extensions
*/
public JacksonJrDecoder(Iterable<JacksonJrExtension> iterable) {
super(iterable);
}
@Override
public Object decode(Response response, Type type) throws IOException {
Transformer transformer = findTransformer(response, type);
if (response.body() == null) {
return null;
}
Reader reader = response.body().asReader(response.charset());
if (!reader.markSupported()) {
reader = new BufferedReader(reader, 1);
}
try {
// Read the first byte to see if we have any data
reader.mark(1);
if (reader.read() == -1) {
return null; // Eagerly returning null avoids "No content to map due to end-of-input"
}
reader.reset();
return transformer.apply(mapper, reader);
} catch (JSONObjectException e) {
if (e.getCause() instanceof IOException) {
throw (IOException) e.getCause();
}
throw e;
}
}
private static Transformer findTransformer(Response response, Type type) {
if (type instanceof Class) {
return (mapper, reader) -> mapper.beanFrom((Class<?>) type, reader);
}
if (type instanceof ParameterizedType) {
Type rawType = ((ParameterizedType) type).getRawType();
Type[] parameterType = ((ParameterizedType) type).getActualTypeArguments();
if (rawType.equals(List.class)) {
return (mapper, reader) -> mapper.listOfFrom((Class<?>) parameterType[0], reader);
}
if (rawType.equals(Map.class)) {
return (mapper, reader) -> mapper.mapOfFrom((Class<?>) parameterType[1], reader);
}
}
throw new DecodeException(500, "Cannot decode type: " + type.getTypeName(), response.request());
}
}

65
jackson-jr/src/main/java/feign/jackson/jr/JacksonJrEncoder.java

@ -0,0 +1,65 @@
/**
* Copyright 2012-2021 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.jackson.jr;
import java.io.IOException;
import java.lang.reflect.Type;
import com.fasterxml.jackson.jr.ob.JSON;
import com.fasterxml.jackson.jr.ob.JacksonJrExtension;
import feign.RequestTemplate;
import feign.codec.EncodeException;
import feign.codec.Encoder;
import static java.lang.String.format;
/**
* A {@link Encoder} that uses Jackson Jr to convert objects to String or byte representation.
*/
public class JacksonJrEncoder extends JacksonJrMapper implements Encoder {
public JacksonJrEncoder() {
super();
}
/**
* Construct with a custom {@link JSON} to use for encoding
*
* @param mapper the mapper to use
*/
public JacksonJrEncoder(JSON mapper) {
super(mapper);
}
/**
* Construct with a series of {@link JacksonJrExtension} objects that are registered into the
* {@link JSON}
*
* @param iterable the source of the extensions
*/
public JacksonJrEncoder(Iterable<JacksonJrExtension> iterable) {
super(iterable);
}
@Override
public void encode(Object object, Type bodyType, RequestTemplate template) {
try {
if (bodyType == byte[].class) {
template.body(mapper.asBytes(object), null);
} else {
template.body(mapper.asString(object));
}
} catch (IOException e) {
throw new EncodeException(e.getMessage(), e);
}
}
}

49
jackson-jr/src/main/java/feign/jackson/jr/JacksonJrMapper.java

@ -0,0 +1,49 @@
/**
* Copyright 2012-2021 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.jackson.jr;
import com.fasterxml.jackson.jr.ob.JSON;
import com.fasterxml.jackson.jr.ob.JacksonJrExtension;
/**
* Common implementation of the holder of a {@link JSON}, DRYing out construction.
*/
abstract class JacksonJrMapper {
protected final JSON mapper;
protected JacksonJrMapper() {
this(JSON.std);
}
/**
* Construct with a custom {@link JSON} to use for decoding/encoding
*
* @param mapper the mapper to use
*/
protected JacksonJrMapper(JSON mapper) {
this.mapper = mapper;
}
/**
* Construct with a series of {@link JacksonJrExtension} objects that are registered into the
* {@link JSON}
*
* @param iterable the source of the extensions
*/
protected JacksonJrMapper(Iterable<JacksonJrExtension> iterable) {
JSON.Builder builder = JSON.builder();
iterable.forEach(builder::register);
this.mapper = builder.build();
}
}

285
jackson-jr/src/test/java/feign/jackson/jr/JacksonCodecTest.java

@ -0,0 +1,285 @@
/**
* Copyright 2012-2021 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.jackson.jr;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.jr.ob.JSON;
import feign.Request;
import feign.Request.HttpMethod;
import feign.RequestTemplate;
import feign.Response;
import feign.Util;
import org.junit.Test;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.time.LocalDate;
import java.util.*;
import static feign.Util.UTF_8;
import static feign.assertj.FeignAssertions.assertThat;
import static java.util.Collections.singletonList;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
public class JacksonCodecTest {
private static final String DATES_JSON = "[\"2020-01-02\",\"2021-02-03\"]";
@Test
public void encodesMapObjectNumericalValuesAsInteger() {
Map<String, Object> map = new LinkedHashMap<>();
map.put("foo", 1);
RequestTemplate template = new RequestTemplate();
new JacksonJrEncoder().encode(map, map.getClass(), template);
assertThat(template).hasBody("{\"foo\":1}");
}
@Test
public void encodesMapObjectNumericalValuesToByteArray() {
Map<String, Object> map = new LinkedHashMap<>();
map.put("foo", 1);
RequestTemplate template = new RequestTemplate();
new JacksonJrEncoder().encode(map, byte[].class, template);
assertThat(template).hasBody("{\"foo\":1}");
}
@Test
public void encodesFormParams() {
Map<String, Object> form = new LinkedHashMap<String, Object>();
form.put("foo", 1);
form.put("bar", Arrays.asList(2, 3));
RequestTemplate template = new RequestTemplate();
new JacksonJrEncoder().encode(form, new TypeReference<Map<String, ?>>() {}.getType(), template);
assertThat(template).hasBody("{\"foo\":1,\"bar\":[2,3]}");
}
@Test
public void decodes() throws Exception {
List<Zone> zones = new LinkedList<>();
zones.add(new Zone("denominator.io."));
zones.add(new Zone("denominator.io.", "ABCD"));
String zonesJson =
"[{\"name\":\"denominator.io.\"},{\"name\":\"denominator.io.\",\"id\":\"ABCD\"}]";
Response response = Response.builder()
.status(200)
.reason("OK")
.request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8))
.headers(Collections.emptyMap())
.body(zonesJson, UTF_8)
.build();
assertEquals(zones,
new JacksonJrDecoder().decode(response, new TypeReference<List<Zone>>() {}.getType()));
}
@Test
public void nullBodyDecodesToNull() throws Exception {
Response response = Response.builder()
.status(204)
.reason("OK")
.request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8))
.headers(Collections.emptyMap())
.build();
assertNull(new JacksonJrDecoder().decode(response, String.class));
}
@Test
public void emptyBodyDecodesToNull() throws Exception {
Response response = Response.builder()
.status(204)
.reason("OK")
.request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8))
.headers(Collections.emptyMap())
.body(new byte[0])
.build();
assertNull(new JacksonJrDecoder().decode(response, String.class));
}
@Test
public void customDecoder() throws Exception {
JacksonJrDecoder decoder = new JacksonJrDecoder(
singletonList(new JavaLocalDateExtension()));
List<LocalDate> dates = new LinkedList<>();
dates.add(LocalDate.of(2020, 1, 2));
dates.add(LocalDate.of(2021, 2, 3));
Response response = Response.builder()
.status(200)
.reason("OK")
.request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8))
.headers(Collections.emptyMap())
.body(DATES_JSON, UTF_8)
.build();
assertEquals(dates,
decoder.decode(response, new TypeReference<List<LocalDate>>() {}.getType()));
}
@Test
public void customDecoderExpressedAsMapper() throws Exception {
JSON mapper = JSON.builder()
.register(new JavaLocalDateExtension())
.build();
JacksonJrDecoder decoder = new JacksonJrDecoder(mapper);
List<LocalDate> dates = new LinkedList<>();
dates.add(LocalDate.of(2020, 1, 2));
dates.add(LocalDate.of(2021, 2, 3));
Response response = Response.builder()
.status(200)
.reason("OK")
.request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8))
.headers(Collections.emptyMap())
.body(DATES_JSON, UTF_8)
.build();
assertEquals(dates,
decoder.decode(response, new TypeReference<List<LocalDate>>() {}.getType()));
}
@Test
public void customEncoder() {
JacksonJrEncoder encoder = new JacksonJrEncoder(
singletonList(new JavaLocalDateExtension()));
List<LocalDate> dates = new LinkedList<>();
dates.add(LocalDate.of(2020, 1, 2));
dates.add(LocalDate.of(2021, 2, 3));
RequestTemplate template = new RequestTemplate();
encoder.encode(dates, new TypeReference<List<LocalDate>>() {}.getType(), template);
assertThat(template).hasBody(DATES_JSON);
}
@Test
public void decoderCharset() throws IOException {
Zone zone = new Zone("denominator.io.", "ÁÉÍÓÚÀÈÌÒÙÄËÏÖÜÑ");
Map<String, Collection<String>> headers = new HashMap<String, Collection<String>>();
headers.put("Content-Type", Arrays.asList("application/json;charset=ISO-8859-1"));
Response response = Response.builder()
.status(200)
.reason("OK")
.request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8))
.headers(headers)
.body(new String("" //
+ "{" + System.lineSeparator()
+ " \"name\" : \"DENOMINATOR.IO.\"," + System.lineSeparator()
+ " \"id\" : \"ÁÉÍÓÚÀÈÌÒÙÄËÏÖÜÑ\"" + System.lineSeparator()
+ "}").getBytes(StandardCharsets.ISO_8859_1))
.build();
assertEquals(zone.getId(),
((Zone) new JacksonJrDecoder().decode(response, Zone.class))
.getId());
}
@Test
public void decodesToMap() throws Exception {
String json = "{\"name\":\"jim\",\"id\":12}";
Response response = Response.builder()
.status(200)
.reason("OK")
.request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8))
.headers(Collections.emptyMap())
.body(json, UTF_8)
.build();
Map<String, Object> map = (Map<String, Object>) new JacksonJrDecoder()
.decode(response, new TypeReference<Map<String, Object>>() {}.getType());
assertEquals(12, map.get("id"));
assertEquals("jim", map.get("name"));
}
public static class Zone {
private String name;
private String id;
public Zone() {
// for reflective instantiation.
}
public Zone(String name) {
this.name = name;
}
public Zone(String name, String id) {
this.name = name;
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
Zone zone = (Zone) o;
return Objects.equals(name, zone.name) && Objects.equals(id, zone.id);
}
@Override
public int hashCode() {
return Objects.hash(name, id);
}
@Override
public String toString() {
return "Zone{" +
"name='" + name + '\'' +
", id='" + id + '\'' +
'}';
}
}
/** Enabled via {@link feign.Feign.Builder#decode404()} */
@Test
public void notFoundDecodesToNull() throws Exception {
Response response = Response.builder()
.status(404)
.reason("NOT FOUND")
.request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8))
.headers(Collections.emptyMap())
.build();
assertThat((byte[]) new JacksonJrDecoder().decode(response, byte[].class)).isNull();
}
}

74
jackson-jr/src/test/java/feign/jackson/jr/JavaLocalDateExtension.java

@ -0,0 +1,74 @@
/**
* Copyright 2012-2021 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.jackson.jr;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.jr.ob.JacksonJrExtension;
import com.fasterxml.jackson.jr.ob.api.ExtensionContext;
import com.fasterxml.jackson.jr.ob.api.ReaderWriterProvider;
import com.fasterxml.jackson.jr.ob.api.ValueReader;
import com.fasterxml.jackson.jr.ob.api.ValueWriter;
import com.fasterxml.jackson.jr.ob.impl.JSONReader;
import com.fasterxml.jackson.jr.ob.impl.JSONWriter;
import java.io.IOException;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
/**
* Adapted from https://www.andersaaberg.dk/2020/enable-support-for-java-time-with-jackson-jr/ This
* adds Java Time support to Jackson JR
*/
public class JavaLocalDateExtension extends JacksonJrExtension {
private static class LocalDateReaderWriterProvider extends ReaderWriterProvider {
@Override
public ValueReader findValueReader(JSONReader readContext, Class<?> type) {
return type == LocalDate.class ? new LocalDateValueReader() : null;
}
@Override
public ValueWriter findValueWriter(JSONWriter writeContext, Class<?> type) {
return type == LocalDate.class ? new LocalDateValueWriter() : null;
}
}
private static class LocalDateValueReader extends ValueReader {
protected LocalDateValueReader() {
super(LocalDate.class);
}
@Override
public Object read(JSONReader reader, JsonParser p) throws IOException {
return LocalDate.parse(p.getText(), DateTimeFormatter.ISO_LOCAL_DATE);
}
}
private static class LocalDateValueWriter implements ValueWriter {
@Override
public void writeValue(JSONWriter context, JsonGenerator g, Object value) throws IOException {
context.writeValue(((LocalDate) value).format(DateTimeFormatter.ISO_LOCAL_DATE));
}
@Override
public Class<?> valueType() {
return LocalDate.class;
}
}
@Override
protected void register(ExtensionContext ctxt) {
ctxt.insertProvider(new LocalDateReaderWriterProvider());
}
}

58
jackson-jr/src/test/java/feign/jackson/jr/examples/GitHubExample.java

@ -0,0 +1,58 @@
/**
* Copyright 2012-2021 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.jackson.jr.examples;
import java.util.List;
import feign.Feign;
import feign.Param;
import feign.RequestLine;
import feign.jackson.jr.JacksonJrDecoder;
/**
* adapted from {@code com.example.retrofit.GitHubClient}
*/
public class GitHubExample {
public static void main(String... args) {
GitHub github = Feign.builder()
.decoder(new JacksonJrDecoder())
.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 {
private String login;
private int contributions;
void setLogin(String login) {
this.login = login;
}
void setContributions(int contributions) {
this.contributions = contributions;
}
}
}

13
pom.xml

@ -33,6 +33,7 @@
<module>hystrix</module> <module>hystrix</module>
<module>jackson</module> <module>jackson</module>
<module>jackson-jaxb</module> <module>jackson-jaxb</module>
<module>jackson-jr</module>
<module>jaxb</module> <module>jaxb</module>
<module>jaxrs</module> <module>jaxrs</module>
<module>jaxrs2</module> <module>jaxrs2</module>
@ -336,6 +337,18 @@
<version>${jackson.version}</version> <version>${jackson.version}</version>
</dependency> </dependency>
<dependency>
<groupId>com.fasterxml.jackson.jr</groupId>
<artifactId>jackson-jr-objects</artifactId>
<version>${jackson.version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.jr</groupId>
<artifactId>jackson-jr-annotation-support</artifactId>
<version>${jackson.version}</version>
</dependency>
<dependency> <dependency>
<groupId>org.slf4j</groupId> <groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId> <artifactId>slf4j-simple</artifactId>

1
src/docs/overview-mindmap.iuml

@ -23,6 +23,7 @@
*** Jackson 1 *** Jackson 1
*** Jackson 2 *** Jackson 2
*** Jackson JAXB *** Jackson JAXB
*** Jackson Jr
*** Sax *** Sax
** metrics ** metrics
*** Dropwizard Metrics 5 *** Dropwizard Metrics 5

Loading…
Cancel
Save