Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions core/src/main/java/feign/Util.java
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Set;
import java.util.function.Predicate;
import static java.lang.String.format;

/**
Expand Down Expand Up @@ -148,6 +149,21 @@ public static String emptyToNull(String string) {
return string == null || string.isEmpty() ? null : string;
}

/**
* Removes values from the array that meet the criteria for removal via the supplied {@link Predicate} value
*/
@SuppressWarnings("unchecked")
public static <T> T[] removeValues(T[] values, Predicate<T> shouldRemove, Class<T> type) {
Collection<T> collection = new ArrayList<>(values.length);
for (T value : values) {
if (shouldRemove.negate().test(value)) {
collection.add(value);
}
}
T[] array = (T[]) Array.newInstance(type, collection.size());
return collection.toArray(array);
}

/**
* Adapted from {@code com.google.common.base.Strings#emptyToNull}.
*/
Expand Down
16 changes: 16 additions & 0 deletions core/src/test/java/feign/UtilTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,28 @@
import java.util.Map;
import java.util.Set;
import feign.codec.Decoder;
import static feign.Util.emptyToNull;
import static feign.Util.removeValues;
import static feign.Util.resolveLastTypeParameter;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.Assert.assertEquals;

public class UtilTest {

@Test
public void removesEmptyStrings() {
String[] values = new String[] {"", null};
assertThat(removeValues(values, (value) -> emptyToNull(value) == null, String.class))
.isEmpty();
}

@Test
public void removesEvenNumbers() {
Integer[] values = new Integer[] {22, 23};
assertThat(removeValues(values, (number) -> number % 2 == 0, Integer.class))
.containsExactly(23);
}

@Test
public void emptyValueOf() throws Exception {
assertEquals(false, Util.emptyValueOf(boolean.class));
Expand Down
4 changes: 2 additions & 2 deletions jaxrs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,9 @@ Sets the request method.
#### `@Path`
Appends the value to `Target.url()`. Can have tokens corresponding to `@PathParam` annotations.
#### `@Produces`
Adds the first value as the `Accept` header.
Adds all values into the `Accept` header.
#### `@Consumes`
Adds the first value as the `Content-Type` header.
Adds all values into the `Content-Type` header.
### Parameter Annotations
#### `@PathParam`
Links the value of the corresponding parameter to a template variable declared in the path.
Expand Down
17 changes: 9 additions & 8 deletions jaxrs/src/main/java/feign/jaxrs/JAXRSContract.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import java.util.Collection;
import static feign.Util.checkState;
import static feign.Util.emptyToNull;
import static feign.Util.removeValues;

/**
* Please refer to the <a href="https://github.com/Netflix/feign/tree/master/feign-jaxrs">Feign
Expand Down Expand Up @@ -99,19 +100,19 @@ protected void processAnnotationOnMethod(MethodMetadata data,
}

private void handleProducesAnnotation(MethodMetadata data, Produces produces, String name) {
String[] serverProduces = produces.value();
String clientAccepts = serverProduces.length == 0 ? null : emptyToNull(serverProduces[0]);
checkState(clientAccepts != null, "Produces.value() was empty on %s", name);
String[] serverProduces =
removeValues(produces.value(), (mediaType) -> emptyToNull(mediaType) == null, String.class);
checkState(serverProduces.length > 0, "Produces.value() was empty on %s", name);
data.template().header(ACCEPT, (String) null); // remove any previous produces
data.template().header(ACCEPT, clientAccepts);
data.template().header(ACCEPT, serverProduces);
}

private void handleConsumesAnnotation(MethodMetadata data, Consumes consumes, String name) {
String[] serverConsumes = consumes.value();
String clientProduces = serverConsumes.length == 0 ? null : emptyToNull(serverConsumes[0]);
checkState(clientProduces != null, "Consumes.value() was empty on %s", name);
String[] serverConsumes =
removeValues(consumes.value(), (mediaType) -> emptyToNull(mediaType) == null, String.class);
checkState(serverConsumes.length > 0, "Consumes.value() was empty on %s", name);
data.template().header(CONTENT_TYPE, (String) null); // remove any previous consumes
data.template().header(CONTENT_TYPE, clientProduces);
data.template().header(CONTENT_TYPE, serverConsumes);
}

/**
Expand Down
27 changes: 27 additions & 0 deletions jaxrs/src/test/java/feign/jaxrs/JAXRSContractTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,16 @@ public void producesAddsAcceptHeader() throws Exception {
entry("Accept", asList("application/xml")));
}

@Test
public void producesMultipleAddsAcceptHeader() throws Exception {
MethodMetadata md = parseAndValidateMetadata(ProducesAndConsumes.class, "producesMultiple");

assertThat(md.template())
.hasHeaders(
entry("Content-Type", asList("application/json")),
entry("Accept", asList("application/xml", "text/plain")));
}

@Test
public void producesNada() throws Exception {
thrown.expect(IllegalStateException.class);
Expand All @@ -145,6 +155,15 @@ public void consumesAddsContentTypeHeader() throws Exception {
entry("Content-Type", asList("application/xml")));
}

@Test
public void consumesMultipleAddsContentTypeHeader() throws Exception {
MethodMetadata md = parseAndValidateMetadata(ProducesAndConsumes.class, "consumesMultiple");

assertThat(md.template())
.hasHeaders(entry("Accept", asList("text/html")),
entry("Content-Type", asList("application/xml", "application/json")));
}

@Test
public void consumesNada() throws Exception {
thrown.expect(IllegalStateException.class);
Expand Down Expand Up @@ -424,6 +443,10 @@ interface ProducesAndConsumes {
@Produces("application/xml")
Response produces();

@GET
@Produces({"application/xml", "text/plain"})
Response producesMultiple();

@GET
@Produces({})
Response producesNada();
Expand All @@ -436,6 +459,10 @@ interface ProducesAndConsumes {
@Consumes("application/xml")
Response consumes();

@POST
@Consumes({"application/xml", "application/json"})
Response consumesMultiple();

@POST
@Consumes({})
Response consumesNada();
Expand Down