diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/json/AbstractJsonParser.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/json/AbstractJsonParser.java new file mode 100644 index 00000000000..c7541292c39 --- /dev/null +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/json/AbstractJsonParser.java @@ -0,0 +1,66 @@ +/* + * Copyright 2012-2018 the original author or 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 org.springframework.boot.json; + +import java.util.List; +import java.util.Map; +import java.util.concurrent.Callable; +import java.util.function.Function; + +import org.springframework.util.ReflectionUtils; + +/** + * Base class for parsers wrapped or implemented in this package. + * + * @author Anton Telechev + * @author Phillip Webb + */ +abstract class AbstractJsonParser implements JsonParser { + + protected final Map parseMap(String json, + Function> parser) { + return trimParse(json, "{", parser); + } + + protected final List parseList(String json, + Function> parser) { + return trimParse(json, "[", parser); + } + + protected final T trimParse(String json, String prefix, + Function parser) { + String trimmed = (json == null ? "" : json.trim()); + if (trimmed.startsWith(prefix)) { + return parser.apply(trimmed); + } + throw new JsonParseException(); + } + + protected final T tryParse(Callable parser, Class check) { + try { + return parser.call(); + } + catch (Exception ex) { + if (check.isAssignableFrom(ex.getClass())) { + throw new JsonParseException(ex); + } + ReflectionUtils.rethrowRuntimeException(ex); + throw new IllegalStateException(ex); + } + } + +} diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/json/BasicJsonParser.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/json/BasicJsonParser.java index ab66f625082..b74f8a65001 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/json/BasicJsonParser.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/json/BasicJsonParser.java @@ -35,28 +35,16 @@ import org.springframework.util.StringUtils; * @since 1.2.0 * @see JsonParserFactory */ -public class BasicJsonParser implements JsonParser { +public class BasicJsonParser extends AbstractJsonParser { @Override public Map parseMap(String json) { - if (json != null) { - json = json.trim(); - if (json.startsWith("{")) { - return parseMapInternal(json); - } - } - throw new IllegalArgumentException("Cannot parse JSON"); + return parseMap(json, this::parseMapInternal); } @Override public List parseList(String json) { - if (json != null) { - json = json.trim(); - if (json.startsWith("[")) { - return parseListInternal(json); - } - } - throw new IllegalArgumentException("Cannot parse JSON"); + return parseList(json, this::parseListInternal); } private List parseListInternal(String json) { diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/json/GsonJsonParser.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/json/GsonJsonParser.java index 127404421ec..428645406b3 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/json/GsonJsonParser.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/json/GsonJsonParser.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -31,7 +31,7 @@ import com.google.gson.reflect.TypeToken; * @since 1.2.0 * @see JsonParserFactory */ -public class GsonJsonParser implements JsonParser { +public class GsonJsonParser extends AbstractJsonParser { private static final TypeToken MAP_TYPE = new MapTypeToken(); @@ -41,24 +41,14 @@ public class GsonJsonParser implements JsonParser { @Override public Map parseMap(String json) { - if (json != null) { - json = json.trim(); - if (json.startsWith("{")) { - return this.gson.fromJson(json, MAP_TYPE.getType()); - } - } - throw new IllegalArgumentException("Cannot parse JSON"); + return parseMap(json, + (trimmed) -> this.gson.fromJson(trimmed, MAP_TYPE.getType())); } @Override public List parseList(String json) { - if (json != null) { - json = json.trim(); - if (json.startsWith("[")) { - return this.gson.fromJson(json, LIST_TYPE.getType()); - } - } - throw new IllegalArgumentException("Cannot parse JSON"); + return parseList(json, + (trimmed) -> this.gson.fromJson(trimmed, LIST_TYPE.getType())); } private static final class MapTypeToken extends TypeToken> { diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/json/JacksonJsonParser.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/json/JacksonJsonParser.java index 1d830c834d5..41651fa1df0 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/json/JacksonJsonParser.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/json/JacksonJsonParser.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -28,7 +28,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; * @author Dave Syer * @see JsonParserFactory */ -public class JacksonJsonParser implements JsonParser { +public class JacksonJsonParser extends AbstractJsonParser { private static final TypeReference MAP_TYPE = new MapTypeReference(); @@ -38,22 +38,14 @@ public class JacksonJsonParser implements JsonParser { @Override public Map parseMap(String json) { - try { - return getObjectMapper().readValue(json, MAP_TYPE); - } - catch (Exception ex) { - throw new IllegalArgumentException("Cannot parse JSON", ex); - } + return tryParse(() -> getObjectMapper().readValue(json, MAP_TYPE), + Exception.class); } @Override public List parseList(String json) { - try { - return getObjectMapper().readValue(json, LIST_TYPE); - } - catch (Exception ex) { - throw new IllegalArgumentException("Cannot parse JSON", ex); - } + return tryParse(() -> getObjectMapper().readValue(json, LIST_TYPE), + Exception.class); } private ObjectMapper getObjectMapper() { diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/json/JsonParseException.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/json/JsonParseException.java new file mode 100644 index 00000000000..10d618fdf99 --- /dev/null +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/json/JsonParseException.java @@ -0,0 +1,36 @@ +/* + * Copyright 2012-2018 the original author or 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 org.springframework.boot.json; + +/** + * {@link IllegalArgumentException} thrown when source JSON is invalid. + * + * @author Anton Telechev + * @author Phillip Webb + * @since 2.0.1 + */ +public class JsonParseException extends IllegalArgumentException { + + public JsonParseException() { + this(null); + } + + public JsonParseException(Throwable cause) { + super("Cannot parse JSON", cause); + } + +} diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/json/JsonParser.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/json/JsonParser.java index 40af7265624..c2cdabb158b 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/json/JsonParser.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/json/JsonParser.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -35,14 +35,16 @@ public interface JsonParser { * Parse the specified JSON string into a Map. * @param json the JSON to parse * @return the parsed JSON as a map + * @throws JsonParseException if the JSON cannot be parsed */ - Map parseMap(String json); + Map parseMap(String json) throws JsonParseException; /** * Parse the specified JSON string into a List. * @param json the JSON to parse * @return the parsed JSON as a list + * @throws JsonParseException if the JSON cannot be parsed */ - List parseList(String json); + List parseList(String json) throws JsonParseException; } diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/json/JsonSimpleJsonParser.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/json/JsonSimpleJsonParser.java index 80b9bd5447a..bdede7e0599 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/json/JsonSimpleJsonParser.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/json/JsonSimpleJsonParser.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -30,28 +30,20 @@ import org.json.simple.parser.ParseException; * @since 1.2.0 * @see JsonParserFactory */ -public class JsonSimpleJsonParser implements JsonParser { +public class JsonSimpleJsonParser extends AbstractJsonParser { @Override @SuppressWarnings("unchecked") public Map parseMap(String json) { - try { - return (Map) new JSONParser().parse(json); - } - catch (ParseException ex) { - throw new IllegalArgumentException("Cannot parse JSON", ex); - } + return (Map) tryParse(() -> new JSONParser().parse(json), + ParseException.class); } @Override @SuppressWarnings("unchecked") public List parseList(String json) { - try { - return (List) new JSONParser().parse(json); - } - catch (ParseException ex) { - throw new IllegalArgumentException("Cannot parse JSON", ex); - } + return (List) tryParse(() -> new JSONParser().parse(json), + ParseException.class); } } diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/json/YamlJsonParser.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/json/YamlJsonParser.java index d2d46536ac5..14c6f68c874 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/json/YamlJsonParser.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/json/YamlJsonParser.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -28,30 +28,18 @@ import org.yaml.snakeyaml.Yaml; * @author Jean de Klerk * @see JsonParserFactory */ -public class YamlJsonParser implements JsonParser { +public class YamlJsonParser extends AbstractJsonParser { @Override @SuppressWarnings("unchecked") public Map parseMap(String json) { - if (json != null) { - json = json.trim(); - if (json.startsWith("{")) { - return new Yaml().loadAs(json, Map.class); - } - } - throw new IllegalArgumentException("Cannot parse JSON"); + return parseMap(json, (trimmed) -> new Yaml().loadAs(trimmed, Map.class)); } @Override @SuppressWarnings("unchecked") public List parseList(String json) { - if (json != null) { - json = json.trim(); - if (json.startsWith("[")) { - return new Yaml().loadAs(json, List.class); - } - } - throw new IllegalArgumentException("Cannot parse JSON"); + return parseList(json, (trimmed) -> new Yaml().loadAs(trimmed, List.class)); } }