我接收JSON
有效载荷,它是键值对的集合。值可以是字符串或数字。我必须解析JSON
,并将键值对存储到适当的varchar2
列中。我应该按照输入有效负载中显示的方式保存传入号码。但对于像1.1E4
、0.00000000000003
和类似的数字,我得到了11000.0
、3.0E-14
。
只使用字符串表示是禁用/阻止数字转换的一种方法吗?
我使用FasterXML
Jackson
实现。顺便说一句,没有实际的文档可用——我找到的所有来源都指向http://wiki.fasterxml.com/JacksonHome它现在正在下降。我在这里发现了两个类似的问题Jackson JSON将整数转换为字符串禁用jackson中的数字到字符串的自动转换但当遇到数字时,两者都需要例外,而我的情况并非如此。我尝试过建议的解决方案,但未能根据我的任务进行修改。
也没有答案https://github.com/FasterXML/jackson-databind/issues/796
现在,除了键值对之外,我没有其他输入字符串的规范。举个例子:
我可能收到类似以下内容:
{"a":"text", "b":"35", "c":{"d":"another"}, "e":["array",35], "f":1.1E4, "g":0.00000000000003}
我想要字符串对
"a" -> "text", "b" -> "35", "c" -> "{"d":"another"}", "e" -> "["array",35]", "f" -> "1.1E4"
最简单的转换方式是:
public void test() throws IOException {
Map map = new ObjectMapper().readValue(
"{"a":"text", "b":"35", "c":{"d":"another"}, "e":["array",35], "f":1.1E4, "g":0.00000000000003}"
, Map.class);
System.out.println(map);
}
结果在:
{a=text, b=35, c={d=another}, e=[array, 35], f=11000.0, g=3.0E-14}
更准确的方法:
public class JsonUtil2 {
private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
public static Map<String, String> parse(String json) throws IOException {
ObjectNode objectNode = (ObjectNode) OBJECT_MAPPER.readTree(json);
Map<String, String> result = new HashMap<>(objectNode.size());
objectNode.fields().forEachRemaining(entry -> result.put(entry.getKey(), toJson(entry.getValue())));
return result;
}
private static String toJson(JsonNode jsonNode) {
if (jsonNode.isNumber()) {
if (jsonNode instanceof DoubleNode || jsonNode instanceof FloatNode) {
DecimalFormatSymbols dfs = new DecimalFormatSymbols();
dfs.setDecimalSeparator('.');
dfs.setMinusSign('-');
DecimalFormat df = new DecimalFormat("#.#", dfs);
df.setMaximumFractionDigits(32);
df.setMaximumIntegerDigits(32);
return df.format(jsonNode.doubleValue());
} else {
return jsonNode.asText();
}
} else if (jsonNode.isValueNode()) {
return jsonNode.asText();
} else {
try {
return OBJECT_MAPPER.writeValueAsString(jsonNode);
} catch (JsonProcessingException e) {
throw new RuntimeException(e);
}
}
}
}
结果是:
{a=text, b=35, c={"d":"another"}, e=["array",35], f=11000, g=0.00000000000003}
这要好得多,但在f=11000
而不是f=1.1E4
中仍然有所不同。
在您的情况下,您希望将所有内容都视为String
,因此需要一个自定义的取消序列化程序,将JSON Object
和JSON Array
读取为String
。我们还可以通过使用TypeFactory
提供该信息来强制Jackson
读取Map<String, String>
。
假设我们的JSON
有效载荷如下所示:
{
"a": "text",
"b": "35",
"c": {
"d": "another",
"dd":3.44E3
},
"e": [
"array",
35,
2.3E5
],
"f": 1.1E4,
"g": 0.00000000000003
}
示例代码:
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonToken;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.deser.std.StringDeserializer;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.type.CollectionType;
import com.fasterxml.jackson.databind.type.MapType;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
public class JsonTreeApp {
public static void main(String[] args) throws Exception {
File jsonFile = new File("./resource/test.json").getAbsoluteFile();
SimpleModule everythingIsStringModule = new SimpleModule();
everythingIsStringModule.addDeserializer(String.class, new EverythingIsStringDeserializer());
ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(everythingIsStringModule);
MapType mapType = mapper.getTypeFactory().constructMapType(LinkedHashMap.class, String.class, String.class);
LinkedHashMap<String, String> map = mapper.readValue(jsonFile, mapType);
map.forEach((k, v) -> System.out.println(k + " => " + v));
}
}
class EverythingIsStringDeserializer extends StringDeserializer {
@Override
public String deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
if (p.currentToken() == JsonToken.START_OBJECT) {
return _deserializeFromObject(p, ctxt);
}
return super.deserialize(p, ctxt);
}
private String _deserializeFromObject(JsonParser p, DeserializationContext ctxt) throws IOException {
MapType mapType = ctxt.getTypeFactory().constructMapType(LinkedHashMap.class, String.class, String.class);
JsonDeserializer<Object> deserializer = ctxt.findRootValueDeserializer(mapType);
Map<String, String> map = (Map<String, String>) deserializer.deserialize(p, ctxt);
return toString(map);
}
@Override
protected String _deserializeFromArray(JsonParser p, DeserializationContext ctxt) throws IOException {
CollectionType collectionType = ctxt.getTypeFactory().constructCollectionType(ArrayList.class, String.class);
JsonDeserializer<Object> deserializer = ctxt.findRootValueDeserializer(collectionType);
List<String> list = (List<String>) deserializer.deserialize(p, ctxt);
return toString(list);
}
private String toString(Map<String, String> map) {
StringBuilder builder = new StringBuilder(128);
builder.append('{');
boolean addComa = false;
for (Map.Entry<String, String> entry : map.entrySet()) {
if (addComa) {
builder.append(',');
}
builder.append('"').append(entry.getKey())
.append("":");
appendValue(entry.getValue(), builder);
addComa = true;
}
builder.append('}');
return builder.toString();
}
private String toString(List<String> list) {
StringBuilder builder = new StringBuilder(128);
builder.append('[');
boolean addComa = false;
for (String item : list) {
if (addComa) {
builder.append(',');
}
appendValue(item, builder);
addComa = true;
}
builder.append(']');
return builder.toString();
}
private void appendValue(String value, StringBuilder builder) {
if (value == null || value.isEmpty()) {
builder.append("""");
return;
}
if (Character.isAlphabetic(value.charAt(0))) {
builder.append('"').append(value).append('"');
} else {
builder.append(value);
}
}
}
打印:
a => text
b => 35
c => {d=another, dd=3.44E3}
e => [array, 35, 2.3E5]
f => 1.1E4
g => 0.00000000000003