Jackson 将多个字段反序列化为一个字段
Deserialize multiple fields to one by Jackson
我关注json
{"val": 501, "scale": 2}
字段 scale
表示值(字段 val
)小数点移动了多少。在这种情况下有 to 地方,因此结果是值 5.01
.
我想将其映射到以下 class
public class ValueClass {
@JsonProperty("val")
@JsonDeserialize(using = ValueDeserializer.class)
private BigDecimal value;
}
我想为此使用自定义反序列化器,但我不清楚如何从反序列化器中访问 JSON 的其他字段,然后是带注释的反序列化器。
@SuppressWarnings("serial")
class ValueDeserializer extends StdDeserializer<BigDecimal> {
protected ValueDeserializer() {
super(BigDecimal.class);
}
@Override
public BigDecimal deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
var val = p.readValueAs(Integer.class);
int scale = ??; // <-- How to access "scale" field here?
return new BigDecimal(val).scaleByPowerOfTen(-scale);
}
}
P.S。我知道我可以 @JsonCreator
在这个简单的案例中。
public class ValueClass {
private BigDecimal value;
@JsonCreator
public ValueClass(//
@JsonProperty("val") Integer val, //
@JsonProperty("scale") Integer scale //
) {
this.value = new BigDecimal(val).scaleByPowerOfTen(-scale);
}
}
尽管如此,实际用例要复杂得多,将逻辑保留在反序列化器中(如果可能)以便于重用会更有好处。
感谢您的帮助。
编辑 1
作为对 Chaosfire 的重播,这里对我的案例进行了更详细的说明。
我需要解析的更真实的 JSON 看起来像这样
{"val1":501, "scale":2, "val2":407, "val3":86}
scale
字段的值被共享为多个字段的分隔符。
JSON对象有大约10个类似上面的字段和50个其他相对简单的字段。我更喜欢反序列化器的原因是为了避免巨大的@JsonCreator,它主要重复输入值。
这对于您当前的设置是不可能的,您只向反序列化器提供 val
节点,但您需要整个对象才能访问 scale
节点。
由于不希望使用 @JsonCreator
,您可以更改反序列化器以处理 ValueClass
:
public class ValueDeserializer extends StdDeserializer<ValueClass> {
public ValueDeserializer() {
super(ValueClass.class);
}
@Override
public ValueClass deserialize(JsonParser parser, DeserializationContext context) throws IOException {
JsonNode node = parser.getCodec().readTree(parser);
int scale = node.get("scale").asInt();
ValueClass valueClass = new ValueClass();
JavaType javaType = context.getTypeFactory().constructType(ValueClass.class);
// Introspect the given type
BeanDescription beanDescription = context.getConfig().introspect(javaType);
// Find properties
List<BeanPropertyDefinition> properties = beanDescription.findProperties();
for (BeanPropertyDefinition property : properties) {
String propertyName = property.getName();//get name as in json
String propertyValue = node.get(propertyName).asText();
BigDecimal decimal = new BigDecimal(propertyValue).scaleByPowerOfTen(-scale);
AnnotatedMember accessor = property.getMutator();
accessor.setValue(valueClass, decimal);
}
return valueClass;
}
}
为避免手动编写 属性 名称和设置它们的值,属性从 java 类型进行内省。这种方法在很大程度上受到 的启发,您可以检查它以获取更多信息和可能的陷阱。我认为设置其余字段应该很简单,以此为基础。
简单测试:
@JsonDeserialize(using = ValueDeserializer.class)
public class ValueClass {
@JsonProperty("val1")
private BigDecimal value1;
private BigDecimal val2;
private BigDecimal val3;
//setters and getters
@Override
public String toString() {
return "ValueClass{" +
"value1=" + value1 +
", val2=" + val2 +
", val3=" + val3 +
'}';
}
}
主要:
public class Main {
public static void main(String[] args) throws Exception {
String json = "{\"val1\":501, \"scale\":2, \"val2\":407, \"val3\":86}";
ObjectMapper mapper = new ObjectMapper();
ValueClass value = mapper.readValue(json, ValueClass.class);
System.out.println(value);
}
}
打印 - ValueClass{value1=5.01, val2=4.07, val3=0.86}
。
我关注json
{"val": 501, "scale": 2}
字段 scale
表示值(字段 val
)小数点移动了多少。在这种情况下有 to 地方,因此结果是值 5.01
.
我想将其映射到以下 class
public class ValueClass {
@JsonProperty("val")
@JsonDeserialize(using = ValueDeserializer.class)
private BigDecimal value;
}
我想为此使用自定义反序列化器,但我不清楚如何从反序列化器中访问 JSON 的其他字段,然后是带注释的反序列化器。
@SuppressWarnings("serial")
class ValueDeserializer extends StdDeserializer<BigDecimal> {
protected ValueDeserializer() {
super(BigDecimal.class);
}
@Override
public BigDecimal deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
var val = p.readValueAs(Integer.class);
int scale = ??; // <-- How to access "scale" field here?
return new BigDecimal(val).scaleByPowerOfTen(-scale);
}
}
P.S。我知道我可以 @JsonCreator
在这个简单的案例中。
public class ValueClass {
private BigDecimal value;
@JsonCreator
public ValueClass(//
@JsonProperty("val") Integer val, //
@JsonProperty("scale") Integer scale //
) {
this.value = new BigDecimal(val).scaleByPowerOfTen(-scale);
}
}
尽管如此,实际用例要复杂得多,将逻辑保留在反序列化器中(如果可能)以便于重用会更有好处。
感谢您的帮助。
编辑 1
作为对 Chaosfire 的重播,这里对我的案例进行了更详细的说明。 我需要解析的更真实的 JSON 看起来像这样
{"val1":501, "scale":2, "val2":407, "val3":86}
scale
字段的值被共享为多个字段的分隔符。
JSON对象有大约10个类似上面的字段和50个其他相对简单的字段。我更喜欢反序列化器的原因是为了避免巨大的@JsonCreator,它主要重复输入值。
这对于您当前的设置是不可能的,您只向反序列化器提供 val
节点,但您需要整个对象才能访问 scale
节点。
由于不希望使用 @JsonCreator
,您可以更改反序列化器以处理 ValueClass
:
public class ValueDeserializer extends StdDeserializer<ValueClass> {
public ValueDeserializer() {
super(ValueClass.class);
}
@Override
public ValueClass deserialize(JsonParser parser, DeserializationContext context) throws IOException {
JsonNode node = parser.getCodec().readTree(parser);
int scale = node.get("scale").asInt();
ValueClass valueClass = new ValueClass();
JavaType javaType = context.getTypeFactory().constructType(ValueClass.class);
// Introspect the given type
BeanDescription beanDescription = context.getConfig().introspect(javaType);
// Find properties
List<BeanPropertyDefinition> properties = beanDescription.findProperties();
for (BeanPropertyDefinition property : properties) {
String propertyName = property.getName();//get name as in json
String propertyValue = node.get(propertyName).asText();
BigDecimal decimal = new BigDecimal(propertyValue).scaleByPowerOfTen(-scale);
AnnotatedMember accessor = property.getMutator();
accessor.setValue(valueClass, decimal);
}
return valueClass;
}
}
为避免手动编写 属性 名称和设置它们的值,属性从 java 类型进行内省。这种方法在很大程度上受到
简单测试:
@JsonDeserialize(using = ValueDeserializer.class)
public class ValueClass {
@JsonProperty("val1")
private BigDecimal value1;
private BigDecimal val2;
private BigDecimal val3;
//setters and getters
@Override
public String toString() {
return "ValueClass{" +
"value1=" + value1 +
", val2=" + val2 +
", val3=" + val3 +
'}';
}
}
主要:
public class Main {
public static void main(String[] args) throws Exception {
String json = "{\"val1\":501, \"scale\":2, \"val2\":407, \"val3\":86}";
ObjectMapper mapper = new ObjectMapper();
ValueClass value = mapper.readValue(json, ValueClass.class);
System.out.println(value);
}
}
打印 - ValueClass{value1=5.01, val2=4.07, val3=0.86}
。