反序列化 JSON - 嵌套列表和键需要作为值
Deserialize JSON - nested lists and key needed as value
我需要用 Jackson 在 Java 1.7 中反序列化它,使用货币作为值:
"prices": {
"USD": [
[1, "1.99000"],
[100, "1.89000"],
[1000, "1.40500"]
],
"EUR": [
[1, "1.53000"],
[100, "1.45000"],
[1000, "1.08350"]
]
}
(来源是这个 REST API https://octopart.com/api/docs/v3/rest-api#notes-partoffer.prices)
我的目标是为每个 Price 获取具有属性 currency、price break 和 price 的对象。
我不知道该怎么做。我尝试了以下方法:
将整个 "prices" 反序列化为 String 以进行进一步处理(没有用,得到 Can not deserialize instance of java.lang.String out of START_OBJECT token - 显然, 因为这是 JSON_OBJECT)
像
反序列化
LinkedHashMap<String, LinkedHashMap<Integer, String>>>
(受到这个Deserializing Jackson by using a key as value的启发,但也没有奏效)
使用这样的包装器:
public class PartOfferPriceWrapper {
private LinkedHashMap<String, List<Entry<Integer, String>>> prices;
}
然后像这样处理:
List<PartOfferPrice> partOfferPriceList = new ArrayList<PartOfferPrice>();
for (Entry<String, List<Entry<Integer, String>>> currencyEntry :
partOfferPrices.entrySet()) {
for (Entry<Integer, String> priceEntry : currencyEntry.getValue()) {
PartOfferPrice partOfferPrice = new PartOfferPrice();
partOfferPrice.setOffer_id(partOfferId);
partOfferPrice.setCurrency(currencyEntry.getKey());
partOfferPrice.setPriceBreak(priceEntry.getKey());
partOfferPrice.setPrice(Double.parseDouble(priceEntry.getValue()));
partOfferPriceList.add(partOfferPrice);
}
这看起来不错,但结果是空的(这是更大响应的一部分,使用 Response.readEntity 读取成功)。我找不到任何其他方法来处理这个(一些自定义解串器?)。
编辑
我尝试按照 tima 的建议使用自定义解串器:
public class PartOfferPricesWrapperDeserializer extends
JsonDeserializer<PartOfferPricesWrapper> {
public PartOfferPricesWrapperDeserializer() { super(); }
@Override
public PartOfferPricesWrapper deserialize(JsonParser jsonParser,
DeserializationContext context) throws IOException,
JsonProcessingException {
PartOfferPricesWrapper partOfferPricesWrapper = new
PartOfferPricesWrapper();
List<PartOfferPrice> priceList = new ArrayList<PartOfferPrice>();
JsonNode node = jsonParser.readValueAsTree();
Iterator<Entry<String, JsonNode>> nodes =
node.get("prices").fields();
while (nodes.hasNext()) {
Map.Entry<String, JsonNode> entry = nodes.next();
for (JsonNode tempNode : entry.getValue()) {
PartOfferPrice price = new PartOfferPrice();
price.setCurrency(entry.getKey());
for (int i = 0; i < tempNode.size(); i++) {
if (tempNode.get(i).isInt()) {
price.setPriceBreak(tempNode.get(i).intValue());
}
else
{
price.setPrice(tempNode.get(i).asDouble());
}
}
priceList.add(price);
}
}
partOfferPricesWrapper.setPrices(priceList);
return partOfferPricesWrapper;
}
}
将其添加到处理程序方法中:
SimpleModule module = new SimpleModule();
module.addDeserializer(PartOfferPricesWrapper.class, new
PartOfferPricesWrapperDeserializer());
objectMapper.registerModule(module);
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES,
false);
partsMatchResponse = objectMapper.readValue(target.getUri().toURL(),
PartsMatchResponse.class);
如果响应仅包含 "prices" 节点,这可能会起作用,但现在我在 node.get("prices").fields(); 上收到 NullPointerException;它可能试图解析整个响应,但我只需要为 "prices" 部分使用自定义解串器。这有可能吗?
非常感谢。
是的,自定义反序列化器可以工作。
class CustomDeserializer extends JsonDeserializer<Prices> {
public CustomDeserializer() { super(); }
@Override
public Prices deserialize(JsonParser jsonParser, DeserializationContext context) throws IOException, JsonProcessingException {
JsonNode node = jsonParser.readValueAsTree();
Iterator<Entry<String, JsonNode>> nodes = node.get("prices").fields();
while (nodes.hasNext()) {
Map.Entry<String, JsonNode> entry = nodes.next();
System.out.println(entry.getKey());
for (JsonNode tempNode : entry.getValue()) {
for (int i = 0; i < tempNode.size(); i++) {
System.out.println(tempNode.get(i).getClass() + "\t" + tempNode.get(i));
}
}
System.out.println();
}
return null;
}
}
输出
USD
class com.fasterxml.jackson.databind.node.IntNode 1
class com.fasterxml.jackson.databind.node.TextNode "1.99000"
class com.fasterxml.jackson.databind.node.IntNode 100
class com.fasterxml.jackson.databind.node.TextNode "1.89000"
class com.fasterxml.jackson.databind.node.IntNode 1000
class com.fasterxml.jackson.databind.node.TextNode "1.40500"
EUR
class com.fasterxml.jackson.databind.node.IntNode 1
class com.fasterxml.jackson.databind.node.TextNode "1.53000"
class com.fasterxml.jackson.databind.node.IntNode 100
class com.fasterxml.jackson.databind.node.TextNode "1.45000"
class com.fasterxml.jackson.databind.node.IntNode 1000
class com.fasterxml.jackson.databind.node.TextNode "1.08350"
你可以在反序列化器中创建你想要的对象和结构(Prices
是一个空的class我用过)。
编辑
您可以对字段使用相同的自定义反序列化器,只需稍作更改。
前两行如下所示,因为您不需要查找 prices
节点,因为当它反序列化该字段时,它只会传递该字段的 JSON 。其余几行相同。
JsonNode node = jsonParser.readValueAsTree();
Iterator<Entry<String, JsonNode>> nodes = node.fields();
然后在你的包装器中 class:
class PricesWrapper {
// ...
@JsonDeserialize(using = CustomDeserializer.class)
private Prices prices;
// ...
}
我需要用 Jackson 在 Java 1.7 中反序列化它,使用货币作为值:
"prices": {
"USD": [
[1, "1.99000"],
[100, "1.89000"],
[1000, "1.40500"]
],
"EUR": [
[1, "1.53000"],
[100, "1.45000"],
[1000, "1.08350"]
]
}
(来源是这个 REST API https://octopart.com/api/docs/v3/rest-api#notes-partoffer.prices)
我的目标是为每个 Price 获取具有属性 currency、price break 和 price 的对象。
我不知道该怎么做。我尝试了以下方法:
将整个 "prices" 反序列化为 String 以进行进一步处理(没有用,得到 Can not deserialize instance of java.lang.String out of START_OBJECT token - 显然, 因为这是 JSON_OBJECT)
像
反序列化LinkedHashMap<String, LinkedHashMap<Integer, String>>>
(受到这个Deserializing Jackson by using a key as value的启发,但也没有奏效)
使用这样的包装器:
public class PartOfferPriceWrapper { private LinkedHashMap<String, List<Entry<Integer, String>>> prices; }
然后像这样处理:
List<PartOfferPrice> partOfferPriceList = new ArrayList<PartOfferPrice>();
for (Entry<String, List<Entry<Integer, String>>> currencyEntry :
partOfferPrices.entrySet()) {
for (Entry<Integer, String> priceEntry : currencyEntry.getValue()) {
PartOfferPrice partOfferPrice = new PartOfferPrice();
partOfferPrice.setOffer_id(partOfferId);
partOfferPrice.setCurrency(currencyEntry.getKey());
partOfferPrice.setPriceBreak(priceEntry.getKey());
partOfferPrice.setPrice(Double.parseDouble(priceEntry.getValue()));
partOfferPriceList.add(partOfferPrice);
}
这看起来不错,但结果是空的(这是更大响应的一部分,使用 Response.readEntity 读取成功)。我找不到任何其他方法来处理这个(一些自定义解串器?)。
编辑
我尝试按照 tima 的建议使用自定义解串器:
public class PartOfferPricesWrapperDeserializer extends
JsonDeserializer<PartOfferPricesWrapper> {
public PartOfferPricesWrapperDeserializer() { super(); }
@Override
public PartOfferPricesWrapper deserialize(JsonParser jsonParser,
DeserializationContext context) throws IOException,
JsonProcessingException {
PartOfferPricesWrapper partOfferPricesWrapper = new
PartOfferPricesWrapper();
List<PartOfferPrice> priceList = new ArrayList<PartOfferPrice>();
JsonNode node = jsonParser.readValueAsTree();
Iterator<Entry<String, JsonNode>> nodes =
node.get("prices").fields();
while (nodes.hasNext()) {
Map.Entry<String, JsonNode> entry = nodes.next();
for (JsonNode tempNode : entry.getValue()) {
PartOfferPrice price = new PartOfferPrice();
price.setCurrency(entry.getKey());
for (int i = 0; i < tempNode.size(); i++) {
if (tempNode.get(i).isInt()) {
price.setPriceBreak(tempNode.get(i).intValue());
}
else
{
price.setPrice(tempNode.get(i).asDouble());
}
}
priceList.add(price);
}
}
partOfferPricesWrapper.setPrices(priceList);
return partOfferPricesWrapper;
}
}
将其添加到处理程序方法中:
SimpleModule module = new SimpleModule();
module.addDeserializer(PartOfferPricesWrapper.class, new
PartOfferPricesWrapperDeserializer());
objectMapper.registerModule(module);
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES,
false);
partsMatchResponse = objectMapper.readValue(target.getUri().toURL(),
PartsMatchResponse.class);
如果响应仅包含 "prices" 节点,这可能会起作用,但现在我在 node.get("prices").fields(); 上收到 NullPointerException;它可能试图解析整个响应,但我只需要为 "prices" 部分使用自定义解串器。这有可能吗?
非常感谢。
是的,自定义反序列化器可以工作。
class CustomDeserializer extends JsonDeserializer<Prices> {
public CustomDeserializer() { super(); }
@Override
public Prices deserialize(JsonParser jsonParser, DeserializationContext context) throws IOException, JsonProcessingException {
JsonNode node = jsonParser.readValueAsTree();
Iterator<Entry<String, JsonNode>> nodes = node.get("prices").fields();
while (nodes.hasNext()) {
Map.Entry<String, JsonNode> entry = nodes.next();
System.out.println(entry.getKey());
for (JsonNode tempNode : entry.getValue()) {
for (int i = 0; i < tempNode.size(); i++) {
System.out.println(tempNode.get(i).getClass() + "\t" + tempNode.get(i));
}
}
System.out.println();
}
return null;
}
}
输出
USD
class com.fasterxml.jackson.databind.node.IntNode 1
class com.fasterxml.jackson.databind.node.TextNode "1.99000"
class com.fasterxml.jackson.databind.node.IntNode 100
class com.fasterxml.jackson.databind.node.TextNode "1.89000"
class com.fasterxml.jackson.databind.node.IntNode 1000
class com.fasterxml.jackson.databind.node.TextNode "1.40500"
EUR
class com.fasterxml.jackson.databind.node.IntNode 1
class com.fasterxml.jackson.databind.node.TextNode "1.53000"
class com.fasterxml.jackson.databind.node.IntNode 100
class com.fasterxml.jackson.databind.node.TextNode "1.45000"
class com.fasterxml.jackson.databind.node.IntNode 1000
class com.fasterxml.jackson.databind.node.TextNode "1.08350"
你可以在反序列化器中创建你想要的对象和结构(Prices
是一个空的class我用过)。
编辑
您可以对字段使用相同的自定义反序列化器,只需稍作更改。
前两行如下所示,因为您不需要查找 prices
节点,因为当它反序列化该字段时,它只会传递该字段的 JSON 。其余几行相同。
JsonNode node = jsonParser.readValueAsTree();
Iterator<Entry<String, JsonNode>> nodes = node.fields();
然后在你的包装器中 class:
class PricesWrapper {
// ...
@JsonDeserialize(using = CustomDeserializer.class)
private Prices prices;
// ...
}