From 32a4476341f493d49134c6108c078addd5bf28d6 Mon Sep 17 00:00:00 2001 From: Tim Gee Date: Tue, 10 Sep 2019 23:30:59 +0100 Subject: [PATCH] First list deserialization test --- .../deser/HttpQueryDeserializer.java | 55 ++++++++++++++++--- .../module/httpquery/ListParamTest.java | 13 +++++ 2 files changed, 60 insertions(+), 8 deletions(-) diff --git a/src/main/java/com/github/trickl/jackson/module/httpquery/deser/HttpQueryDeserializer.java b/src/main/java/com/github/trickl/jackson/module/httpquery/deser/HttpQueryDeserializer.java index 2c83bbd..a36a1b6 100644 --- a/src/main/java/com/github/trickl/jackson/module/httpquery/deser/HttpQueryDeserializer.java +++ b/src/main/java/com/github/trickl/jackson/module/httpquery/deser/HttpQueryDeserializer.java @@ -21,6 +21,7 @@ import com.fasterxml.jackson.databind.deser.SettableBeanProperty; import com.fasterxml.jackson.databind.deser.ValueInstantiator; import com.fasterxml.jackson.databind.deser.std.StdDeserializer; +import com.github.trickl.jackson.module.httpquery.annotations.HttpQueryDelimited; import java.io.IOException; import java.io.StringReader; @@ -28,6 +29,13 @@ import java.net.URLDecoder; import java.nio.charset.StandardCharsets; import java.text.MessageFormat; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; public class HttpQueryDeserializer extends StdDeserializer { @@ -65,8 +73,8 @@ public Object deserialize(JsonParser jp, DeserializationContext ctxt) final Object bean = valueInstantiator.createUsingDefault(ctxt); String[] nameValueParams = queryString.split("&"); - for (String nameValueParam : nameValueParams) { - + Map> params = new HashMap<>(); + for (String nameValueParam : nameValueParams) { String name; String value = null; if (nameValueParam.contains("=")) { @@ -76,8 +84,12 @@ public Object deserialize(JsonParser jp, DeserializationContext ctxt) } else { name = decode(nameValueParam); } + params.computeIfAbsent(name, n -> new ArrayList<>()); + params.get(name).add(value); + } - SettableBeanProperty prop = beanDeserializer.findProperty(new PropertyName(name)); + for (Map.Entry> param : params.entrySet()) { + SettableBeanProperty prop = beanDeserializer.findProperty(new PropertyName(param.getKey())); if (prop == null) { if (ignoreUnknown) { continue; @@ -85,12 +97,12 @@ public Object deserialize(JsonParser jp, DeserializationContext ctxt) String errorMessage = MessageFormat.format( "Unknown parameter \"{0}\" supplied.", - new Object[] {name}); + new Object[] {param.getKey()}); throw new JsonParseException(jp, errorMessage); } } - deserializeNameValue(value, prop, jp, ctxt, bean); + deserializeNameValue(param.getValue(), prop, jp, ctxt, bean); } return bean; @@ -104,13 +116,35 @@ private String decode(String value) throws UnsupportedEncodingException { * Set an object value using the supplied query param. */ public void deserializeNameValue( - String value, + List values, SettableBeanProperty prop, JsonParser p, DeserializationContext ctxt, Object bean) throws IOException { - StringReader reader = new StringReader(quoted(value)); + + String jsonifiedParam = ""; + JavaType propType = prop.getType(); + boolean isArrayOrCollection = + prop.getType().isTypeOrSubTypeOf(Collection.class) + || prop.getType().isArrayType(); + if (isArrayOrCollection) { + 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); + } else { + String lastValue = values.get(values.size() - 1); + if (propType.isPrimitive()) { + jsonifiedParam = lastValue; + } else { + jsonifiedParam = quote(lastValue); + } + } + + StringReader reader = new StringReader(jsonifiedParam); JsonParser parser = new ReaderBasedJsonParser( getIoContext(), p.getFeatureMask(), @@ -141,7 +175,12 @@ private CharsToNameCanonicalizer getCharsToNameCanonicalizer() { return CharsToNameCanonicalizer.createRoot(); } - private String quoted(String value) { + private String quote(String value) { return '"' + value + '"'; } + + private String wrapAsArray(List values) { + return "[" + values.stream().map(this::quote) + .collect(Collectors.joining(" ,")) + "]"; + } } diff --git a/src/test/java/com/github/trickl/jackson/module/httpquery/ListParamTest.java b/src/test/java/com/github/trickl/jackson/module/httpquery/ListParamTest.java index 2185bb4..62acadd 100644 --- a/src/test/java/com/github/trickl/jackson/module/httpquery/ListParamTest.java +++ b/src/test/java/com/github/trickl/jackson/module/httpquery/ListParamTest.java @@ -2,6 +2,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals; +import java.io.IOException; import java.util.Arrays; import java.util.List; @@ -16,6 +17,9 @@ import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; + public class ListParamTest { private static ObjectMapper objectMapper; @@ -73,6 +77,8 @@ public CustomDelimiterListQuery(List values) { } @HttpQuery + @NoArgsConstructor + @EqualsAndHashCode private static class CustomDelimiterNoEncodeListQuery { @JsonProperty("paramA") @HttpQueryDelimited(delimiter = ";", encodeDelimiter = false) @@ -117,4 +123,11 @@ public void testCustomDelimiterNoEncodeListSerialization() throws JsonProcessing objectMapper.writeValueAsString( new CustomDelimiterNoEncodeListQuery(EXAMPLE_LIST))); } + + @Test + public void testCustomDelimiterNoEncodeListDeserialization() throws IOException { + assertEquals(new CustomDelimiterNoEncodeListQuery(EXAMPLE_LIST), + objectMapper.readValue("\"?paramA=first;second;third\"", + CustomDelimiterNoEncodeListQuery.class)); + } }