Skip to content

Commit

Permalink
Fix up all list and array deserialisation tests
Browse files Browse the repository at this point in the history
  • Loading branch information
trickl committed Sep 11, 2019
1 parent 32a4476 commit 56490a1
Show file tree
Hide file tree
Showing 5 changed files with 144 additions and 18 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,9 @@ public Object findDeserializer(Annotated am) {
HttpQuery annotation = am.getAnnotation(HttpQuery.class);
return new HttpQueryDeserializer(
am.getType(),
annotation.ignoreUnknown());
annotation.ignoreUnknown(),
annotation.encodeNames(),
annotation.encodeValues());
}
return null;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import java.io.StringReader;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.text.MessageFormat;
import java.util.ArrayList;
Expand All @@ -43,12 +44,20 @@ public class HttpQueryDeserializer extends StdDeserializer<Object> {

private final JavaType javaType;
private final boolean ignoreUnknown;
private final boolean decodeNames;
private final boolean decodeValues;

/** Create a deserializer for converting a Http query string to a typed object. */
public HttpQueryDeserializer(JavaType javaType, boolean ignoreUnknown) {
public HttpQueryDeserializer(
JavaType javaType,
boolean ignoreUnknown,
boolean decodeNames,
boolean decodeValues) {
super(Object.class);
this.javaType = javaType;
this.ignoreUnknown = ignoreUnknown;
this.decodeNames = decodeNames;
this.decodeValues = decodeValues;
}

@Override
Expand Down Expand Up @@ -76,16 +85,17 @@ public Object deserialize(JsonParser jp, DeserializationContext ctxt)
Map<String, List<String>> params = new HashMap<>();
for (String nameValueParam : nameValueParams) {
String name;
String value = null;
String encodedValue = null;
if (nameValueParam.contains("=")) {
name = decode(nameValueParam.substring(0, nameValueParam.indexOf('=')));
value = decode(nameValueParam.substring(
nameValueParam.indexOf('=') + 1, nameValueParam.length()));
String encodedName = nameValueParam.substring(0, nameValueParam.indexOf('='));
name = decodeNames ? decode(encodedName) : encodedName;
encodedValue = nameValueParam.substring(
nameValueParam.indexOf('=') + 1, nameValueParam.length());
} else {
name = decode(nameValueParam);
name = decodeNames ? decode(nameValueParam) : nameValueParam;
}
params.computeIfAbsent(name, n -> new ArrayList<>());
params.get(name).add(value);
params.get(name).add(encodedValue);
}

for (Map.Entry<String, List<String>> param : params.entrySet()) {
Expand All @@ -112,11 +122,15 @@ private String decode(String value) throws UnsupportedEncodingException {
return URLDecoder.decode(value, StandardCharsets.UTF_8.toString());
}

private String encode(String value) throws UnsupportedEncodingException {
return URLEncoder.encode(value, StandardCharsets.UTF_8.toString());
}

/**
* Set an object value using the supplied query param.
*/
public void deserializeNameValue(
List<String> values,
List<String> encodedValues,
SettableBeanProperty prop,
JsonParser p,
DeserializationContext ctxt,
Expand All @@ -129,14 +143,26 @@ public void deserializeNameValue(
prop.getType().isTypeOrSubTypeOf(Collection.class)
|| prop.getType().isArrayType();
if (isArrayOrCollection) {
boolean shouldDecode = decodeValues;
HttpQueryDelimited delimited = prop.getAnnotation(HttpQueryDelimited.class);
if (delimited != null) {
String lastValue = values.get(values.size() - 1);
values = Arrays.asList(lastValue.split(delimited.delimiter()));
}
jsonifiedParam = wrapAsArray(values);
String lastValue = encodedValues.get(encodedValues.size() - 1);
String delimiter = delimited.delimiter();
shouldDecode = delimited.encodeValues();
String encodedDelimiter = delimited.encodeDelimiter() ? encode(delimiter) : delimiter;
encodedValues = Arrays.asList(lastValue.split(encodedDelimiter));
}

List<String> decodedValues = new ArrayList<>();
for (String encodedValue : encodedValues) {
String decodedValue = shouldDecode ? decode(encodedValue) : encodedValue;
decodedValues.add(decodedValue);
}

jsonifiedParam = wrapAsArray(encodedValues);
} else {
String lastValue = values.get(values.size() - 1);
String encodedLastValue = encodedValues.get(encodedValues.size() - 1);
String lastValue = decodeValues ? decode(encodedLastValue) : encodedLastValue;
if (propType.isPrimitive()) {
jsonifiedParam = lastValue;
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ public boolean serializeAsNameValue(
StringWriter valueWriter = new StringWriter();
Object propValue = prop.get(bean);
String propName = prop.getName();
JavaType propType = prop.getType();
String name = encodeNames ? encode(propName) : propName;

try (QuotelessStringGenerator valueGenerator =
Expand All @@ -96,10 +97,10 @@ public boolean serializeAsNameValue(
} else {
provider.findNullValueSerializer(prop).serialize(propValue, valueGenerator, provider);
}
} else if (prop.getType().isTypeOrSubTypeOf(Collection.class)
|| prop.getType().isArrayType()) {
} else if (propType.isTypeOrSubTypeOf(Collection.class)
|| propType.isArrayType()) {
Collection<?> collection = Collections.emptyList();
if (prop.getType().isTypeOrSubTypeOf(Collection.class)) {
if (propType.isTypeOrSubTypeOf(Collection.class)) {
collection = (Collection<?>) propValue;
} else {
AtomicInteger index = new AtomicInteger(0);
Expand All @@ -113,7 +114,7 @@ public boolean serializeAsNameValue(
if (annotatedList != null) {
HttpQueryDelimitedSerializer serializer =
new HttpQueryDelimitedSerializer(
prop.getType(),
propType,
annotatedList.delimiter(),
annotatedList.encodeDelimiter(),
encodeValues);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import static org.junit.jupiter.api.Assertions.assertEquals;

import java.io.IOException;
import java.util.Arrays;

import com.fasterxml.jackson.annotation.JsonIgnore;
Expand All @@ -15,6 +16,10 @@
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;

import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import lombok.ToString;

public class ArrayParamTest {

private static ObjectMapper objectMapper;
Expand All @@ -29,6 +34,9 @@ public static void setup() {
}

@HttpQuery
@NoArgsConstructor
@EqualsAndHashCode
@ToString
private static class RegularArrayQuery {
@JsonProperty("paramA")
private String[] values;
Expand All @@ -39,6 +47,9 @@ public RegularArrayQuery(String[] values) {
}

@HttpQuery
@NoArgsConstructor
@EqualsAndHashCode
@ToString
private static class DelimitedArrayQuery {
@JsonProperty("paramA")
@HttpQueryDelimited
Expand All @@ -50,6 +61,9 @@ public DelimitedArrayQuery(String[] values) {
}

@HttpQuery
@NoArgsConstructor
@EqualsAndHashCode
@ToString
private static class DelimitedArrayNoEncodeQuery {
@JsonProperty("paramA")
@HttpQueryDelimited(encodeDelimiter = false)
Expand All @@ -61,6 +75,9 @@ public DelimitedArrayNoEncodeQuery(String[] values) {
}

@HttpQuery
@NoArgsConstructor
@EqualsAndHashCode
@ToString
private static class CustomDelimiterArrayQuery {
@JsonProperty("paramA")
@HttpQueryDelimited(delimiter = ";")
Expand All @@ -72,6 +89,9 @@ public CustomDelimiterArrayQuery(String[] values) {
}

@HttpQuery
@NoArgsConstructor
@EqualsAndHashCode
@ToString
private static class CustomDelimiterNoEncodeArrayQuery {
@JsonProperty("paramA")
@HttpQueryDelimited(delimiter = ";", encodeDelimiter = false)
Expand All @@ -89,31 +109,66 @@ public void testRegularArraySerialization() throws JsonProcessingException {
new RegularArrayQuery(EXAMPLE_ARRAY)));
}

@Test
public void testRegularArrayDeserialization() throws IOException {
assertEquals(new RegularArrayQuery(EXAMPLE_ARRAY),
objectMapper.readValue("\"?paramA=first&paramA=second&paramA=third\"",
RegularArrayQuery.class));
}

@Test
public void testDelimitedArraySerialization() throws JsonProcessingException {
assertEquals("?paramA=first%2Csecond%2Cthird",
objectMapper.writeValueAsString(
new DelimitedArrayQuery(EXAMPLE_ARRAY)));
}

@Test
public void testDelimitedArrayDeserialization() throws IOException {
assertEquals(new DelimitedArrayQuery(EXAMPLE_ARRAY),
objectMapper.readValue("\"?paramA=first%2Csecond%2Cthird\"",
DelimitedArrayQuery.class));
}

@Test
public void testDelimitedArrayNoEncodeSerialization() throws JsonProcessingException {
assertEquals("?paramA=first,second,third",
objectMapper.writeValueAsString(
new DelimitedArrayNoEncodeQuery(EXAMPLE_ARRAY)));
}

@Test
public void testDelimitedArrayNoEncodeDeserialization() throws IOException {
assertEquals(new DelimitedArrayNoEncodeQuery(EXAMPLE_ARRAY),
objectMapper.readValue("\"?paramA=first,second,third\"",
DelimitedArrayNoEncodeQuery.class));
}

@Test
public void testCustomDelimiterArraySerialization() throws JsonProcessingException {
assertEquals("?paramA=first%3Bsecond%3Bthird",
objectMapper.writeValueAsString(
new CustomDelimiterArrayQuery(EXAMPLE_ARRAY)));
}

@Test
public void testCustomDelimiterArrayDeserialization() throws IOException {
assertEquals(new CustomDelimiterArrayQuery(EXAMPLE_ARRAY),
objectMapper.readValue("\"?paramA=first%3Bsecond%3Bthird\"",
CustomDelimiterArrayQuery.class));
}

@Test
public void testCustomDelimiterNoEncodeArraySerialization() throws JsonProcessingException {
assertEquals("?paramA=first;second;third",
objectMapper.writeValueAsString(
new CustomDelimiterNoEncodeArrayQuery(EXAMPLE_ARRAY)));
}

@Test
public void testCustomDelimiterNoEncodeArrayDeserialization() throws IOException {
assertEquals(new CustomDelimiterNoEncodeArrayQuery(EXAMPLE_ARRAY),
objectMapper.readValue("\"?paramA=first;second;third\"",
CustomDelimiterNoEncodeArrayQuery.class));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import lombok.ToString;

public class ListParamTest {

Expand All @@ -34,6 +35,9 @@ public static void setup() {
}

@HttpQuery
@NoArgsConstructor
@EqualsAndHashCode
@ToString
private static class RegularListQuery {
@JsonProperty("paramA")
private List<String> values;
Expand All @@ -44,6 +48,9 @@ public RegularListQuery(List<String> values) {
}

@HttpQuery
@NoArgsConstructor
@EqualsAndHashCode
@ToString
private static class DelimitedListQuery {
@JsonProperty("paramA")
@HttpQueryDelimited
Expand All @@ -55,6 +62,9 @@ public DelimitedListQuery(List<String> values) {
}

@HttpQuery
@NoArgsConstructor
@EqualsAndHashCode
@ToString
private static class DelimitedListNoEncodeQuery {
@JsonProperty("paramA")
@HttpQueryDelimited(encodeDelimiter = false)
Expand All @@ -66,6 +76,9 @@ public DelimitedListNoEncodeQuery(List<String> values) {
}

@HttpQuery
@NoArgsConstructor
@EqualsAndHashCode
@ToString
private static class CustomDelimiterListQuery {
@JsonProperty("paramA")
@HttpQueryDelimited(delimiter = ";")
Expand All @@ -79,6 +92,7 @@ public CustomDelimiterListQuery(List<String> values) {
@HttpQuery
@NoArgsConstructor
@EqualsAndHashCode
@ToString
private static class CustomDelimiterNoEncodeListQuery {
@JsonProperty("paramA")
@HttpQueryDelimited(delimiter = ";", encodeDelimiter = false)
Expand All @@ -96,27 +110,55 @@ public void testRegularListSerialization() throws JsonProcessingException {
new RegularListQuery(EXAMPLE_LIST)));
}

@Test
public void testRegularListDeserialization() throws IOException {
assertEquals(new RegularListQuery(EXAMPLE_LIST),
objectMapper.readValue("\"?paramA=first&paramA=second&paramA=third\"",
RegularListQuery.class));
}

@Test
public void testDelimitedListSerialization() throws JsonProcessingException {
assertEquals("?paramA=first%2Csecond%2Cthird",
objectMapper.writeValueAsString(
new DelimitedListQuery(EXAMPLE_LIST)));
}

@Test
public void testDelimitedListDeserialization() throws IOException {
assertEquals(new DelimitedListQuery(EXAMPLE_LIST),
objectMapper.readValue("\"?paramA=first%2Csecond%2Cthird\"",
DelimitedListQuery.class));
}

@Test
public void testDelimitedListNoEncodeSerialization() throws JsonProcessingException {
assertEquals("?paramA=first,second,third",
objectMapper.writeValueAsString(
new DelimitedListNoEncodeQuery(EXAMPLE_LIST)));
}

@Test
public void testDelimitedListNoEncodeDeserialization() throws IOException {
assertEquals(new DelimitedListNoEncodeQuery(EXAMPLE_LIST),
objectMapper.readValue("\"?paramA=first,second,third\"",
DelimitedListNoEncodeQuery.class));
}

@Test
public void testCustomDelimiterListSerialization() throws JsonProcessingException {
assertEquals("?paramA=first%3Bsecond%3Bthird",
objectMapper.writeValueAsString(
new CustomDelimiterListQuery(EXAMPLE_LIST)));
}

@Test
public void testCustomDelimiterListDeserialization() throws IOException {
assertEquals(new CustomDelimiterListQuery(EXAMPLE_LIST),
objectMapper.readValue("\"?paramA=first%3Bsecond%3Bthird\"",
CustomDelimiterListQuery.class));
}

@Test
public void testCustomDelimiterNoEncodeListSerialization() throws JsonProcessingException {
assertEquals("?paramA=first;second;third",
Expand Down

0 comments on commit 56490a1

Please sign in to comment.