我想用杰克逊解析下面的Json,但我不确定如何构建实体。
[
CHAN_ID,
[
[
SYMBOL,
STATUS,
AMOUNT,
BASE_PRICE,
MARGIN_FUNDING,
MARGIN_FUNDING_TYPE,
PL,
PL_PERC,
PRICE_LIQ,
LEVERAGE,
...
],
...
]
]
这是我到目前为止所做的:
@Getter
@Setter
@EqualsAndHashCode
@ToString
@NoArgsConstructor
public class Position {
@JsonProperty("SYMBOL")
private String symbol;
@JsonProperty("STATUS")
private String status;
@JsonProperty("AMOUNT")
private Decimal amount;
@JsonProperty("BASE_PRICE")
private Decimal basePrice;
@JsonProperty("MARGIN_FUNDING")
private Integer marginFunding;
@JsonProperty("MARGIN_FUNDING_TYPE")
private Decimal marginFundingType;
@JsonProperty("PL")
private Decimal profitLoss;
@JsonProperty("PL_PERC")
private Decimal profitLossPercentage;
@JsonProperty("PRICE_LIQ")
private Decimal liquidationPrice;
@JsonProperty("LEVERAGE")
private Decimal leverage;
}
这个我试图解析的东西,似乎有一个Position数组,但在它有CHAN_ID之前,我应该为它构造某种包装类吗?
@Getter
@Setter
@EqualsAndHashCode
@ToString
@NoArgsConstructor
public class Positions {
@JsonProperty("CHAN_ID")
private String channelId;
@JsonProperty("positions")
private List<Position> positions;
}
您怎么看?这是对的吗?也不要介意那些顶级类的注释,它只是龙目岛。 目前,当我尝试解析时,此实现会给我以下错误:
com.fasterxml.jackson.databind.exc.MismatchedInputException:不能 在START_ARRAY令牌中反序列化
model.Positions
的实例 [来源:( String)“['ps',[['aa','bb',123.45,123.45,567,123.45, 123.45,123.45,123.45,123.45]]]“;行:1,栏目:1]
为了测试这个我只是使用ObjectMapper:
public static void main(String[] args) throws IOException {
ObjectMapper objectMapper = new ObjectMapper();
try {
Positions positions = objectMapper.readValue("['ps', [ [ 'aa', 'bb', 123.45, 123.45, 567, 123.45, 123.45, 123.45, 123.45, 123.45]] ]", Positions.class);
} catch (IOException e) {
e.printStackTrace();
}
}
答案 0 :(得分:1)
由于输入JSON的结构是嵌套数组,因此与@JsonProperty
的绑定没有多大意义,因为输入JSON中不存在这些属性键。只有当你想要将反序列化的数据转换为具有属性 - 值对的JSON时,它们才有意义。
要正确读取此JSON结构,您必须实现自定义反序列化器,因为在这种情况下,属性无法自动映射其值。解串器可以是杰克逊JsonDeserializer
或StdDeserializer
的实现。例如,以下实现有效:
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
import java.io.IOException;
import java.util.List;
import java.util.stream.Collectors;
public class PositionsDeserializer extends StdDeserializer<Positions> {
public PositionsDeserializer() {
super(Positions.class);
}
@Override
public Positions deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
Object[] positionsProps = p.readValueAs(Object[].class);
if (positionsProps != null && positionsProps.length > 0) {
String chanId = (String) positionsProps[0];
List<Position> positionsList =
((List<List<?>>) positionsProps[1]).stream()
.map(this::deserializePosition)
.collect(Collectors.toList());
Positions positions = new Positions();
positions.setChannelId(chanId);
positions.setPositions(positionsList);
return positions;
}
// decide whether you want to return null, throw an exception or other outcome: depends on the constraints of your data
return null;
}
private Position deserializePosition(List<?> props) {
if (props != null && !props.isEmpty()) {
final Position position = new Position();
position.setSymbol((String) props.get(0));
position.setStatus((String) props.get(1));
position.setAmount((Double) props.get(2));
position.setBasePrice((Double) props.get(3));
position.setMarginFunding((Integer) props.get(4));
position.setMarginFundingType((Double) props.get(5));
position.setProfitLoss((Double) props.get(6));
position.setProfitLossPercentage((Double) props.get(7));
position.setLiquidationPrice((Double) props.get(8));
position.setLeverage((Double) props.get(9));
return position;
}
// decide whether you want to return null, throw an exception or other outcome: depends on the constraints of your data
return null;
}
}
要使用此反序列化程序,应在ObjectMapper
:
private ObjectMapper initObjectMapper() {
ObjectMapper objectMapper = new ObjectMapper();
SimpleModule module = new SimpleModule();
module.addDeserializer(Positions.class, new PositionsDeserializer());
objectMapper.registerModule(module);
return objectMapper;
}
@Test
public void deserializePositions() throws IOException {
String json = "[ \"ps\", [ [ \"aa\", \"bb\", 123.45, 123.45, 567, 123.45, 123.45, 123.45, 123.45, 123.45 ] ] ]";
Positions positions = initObjectMapper().readValue(json, Positions.class);
System.out.println(positions);
}
建议
如果您有可能选择/更改输入JSON的结构,我建议减少嵌套并引入更多传统的KV映射。例如,代表Positions
:
{
"CHAN_ID": "string",
"positions": [
// Use the arrays here: [ "aa", "bb", 123.45, 123.45, 567, 123.45, 123.45, 123.45, 123.45, 123.45 ],
// OR transform the array into KV mapping: { "SYMBOL": "string", ... }, ...
]
}
这种方法将允许:
降低由与数组索引相关的幻数引起的错误风险;
简化反序列化:如果保留数组结构,则自动读取Positions
并仅为Position
设置自定义反序列化器。
另外,我不知道原始代码中Decimal
类型的含义,因此我将其替换为Double
。