Commit aa696210 authored by Anton Telechev's avatar Anton Telechev Committed by Phillip Webb

Refactor spring-boot JSON parsers

Refactor JSON parser wrappers to remove duplicate code portions in the
parseMap() and parseList() methods by adding an AbstractJsonParser.

See gh-12428
parent a4b0be08
/*
* Copyright 2012-2017 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.Optional;
import java.util.function.Function;
/**
* Base class for parsers wrapped or implemented in this package.
*
* @author Anton Telechev
*/
abstract class AbstractJsonParser implements JsonParser {
/** Start symbol of a JSON map. **/
private static final String START_MAP = "{";
/** Start symbol of a JSON list. **/
private static final String START_LIST = "[";
/**
* Parses the specified JSON string and returns the extracted contents as a Map of
* String to Object.
*
* @param json the JSON string to parse.
* @param parser the parser function.
* @return Map<String, Object> parsed contents
* @throws IllegalArgumentException if the json String cannot be parsed as a
* Map<String, Object>
*/
Map<String, Object> parseMap(String json,
Function<String, Map<String, Object>> parser) {
assert parser != null;
return trimIfStartsWith(json, START_MAP).map(parser::apply)
.orElseThrow(AbstractJsonParser::cannotParseJson);
}
/**
* Parses the specified JSON string and returns the extracted contents as a List of Objects.
*
* @param json the JSON string to parse.
* @param parser the parser function.
* @return List&lt;Object&gt; parsed contents
* @throws IllegalArgumentException if the json String cannot be parsed as a
* List&lt;Object&gt;
*/
List<Object> parseList(String json, Function<String, List<Object>> parser) {
assert parser != null;
return trimIfStartsWith(json, START_LIST).map(parser::apply)
.orElseThrow(AbstractJsonParser::cannotParseJson);
}
private static IllegalArgumentException cannotParseJson() {
return cannotParseJson(null);
}
static IllegalArgumentException cannotParseJson(Exception cause) {
return new IllegalArgumentException("Cannot parse JSON", cause);
}
private static Optional<String> trimIfStartsWith(String json, String expectedPrefix) {
assert expectedPrefix != null;
if (json != null) {
final String trimmed = json.trim();
if (trimmed.startsWith(expectedPrefix)) {
return Optional.of(trimmed);
}
}
return Optional.empty();
}
}
......@@ -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<String, Object> 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<Object> 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<Object> parseListInternal(String json) {
......
......@@ -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<String, Object> 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<Object> 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<Map<String, Object>> {
......
......@@ -42,7 +42,7 @@ public class JacksonJsonParser implements JsonParser {
return getObjectMapper().readValue(json, MAP_TYPE);
}
catch (Exception ex) {
throw new IllegalArgumentException("Cannot parse JSON", ex);
throw AbstractJsonParser.cannotParseJson(ex);
}
}
......@@ -52,7 +52,7 @@ public class JacksonJsonParser implements JsonParser {
return getObjectMapper().readValue(json, LIST_TYPE);
}
catch (Exception ex) {
throw new IllegalArgumentException("Cannot parse JSON", ex);
throw AbstractJsonParser.cannotParseJson(ex);
}
}
......
......@@ -39,7 +39,7 @@ public class JsonSimpleJsonParser implements JsonParser {
return (Map<String, Object>) new JSONParser().parse(json);
}
catch (ParseException ex) {
throw new IllegalArgumentException("Cannot parse JSON", ex);
throw AbstractJsonParser.cannotParseJson(ex);
}
}
......@@ -50,7 +50,7 @@ public class JsonSimpleJsonParser implements JsonParser {
return (List<Object>) new JSONParser().parse(json);
}
catch (ParseException ex) {
throw new IllegalArgumentException("Cannot parse JSON", ex);
throw AbstractJsonParser.cannotParseJson(ex);
}
}
......
......@@ -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<String, Object> 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<Object> 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));
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment