我在我的应用程序中使用Jackson进行de / serialization。
我有一种情况需要将JSON字符串转换为我的3个类之一。如果字符串不能转换为3个类别中的任何一个,那么它将被认为是一个无法识别的情况。
但是,如果json字符串的架构与mapper.readValue(jsonString,MyClass1.class)
中提供的类不匹配,则会抛出UnrecognizedPropertyException
。
目前我正在使用类似下面的内容,但它看起来非常混乱。
try {
obj = mapper.readValue(jsonString, MyClass1.class);
} catch (UnrecognizedPropertyException e1) {
try {
obj = mapper.readValue(jsonString, MyClass2.class);
} catch (UnrecognizedPropertyException e2) {
try {
obj = mapper.readValue(jsonString, MyClass3.class);
} catch (Exception e) {
//handle unrecognized string
}
} catch (Exception e) {
//handle unrecognized string
}
} catch (Exception e) {
//handle unrecognized string
}
这是它需要完成的方式还是有其他选择?是否有任何方法可以将mapper
配置为在无法识别的属性的情况下返回null
,因为这会导致创建简单的系列if
块而不是嵌套的try-catch
块?
答案 0 :(得分:1)
您可以尝试使用此方法进行反序列化。这将在null
上返回UnrecognizedPropertyException
:
private <T> T deserialize(ObjectMapper mapper, Class<T> type, String jsonString) {
T t = null;
try {
t = mapper.readValue(jsonString, type);
} catch (UnrecognizedPropertyException e) {
//handle unrecognized string
}catch (IOException e) {
//handle under errors
}
return t;
}
答案 1 :(得分:0)
如果您生成jsonString
,则可以考虑添加type info
,然后使用它来转换反序列化对象。您可以参考this post了解如何操作。
如果jsonString
由您无法控制的其他服务生成,那么您无法获得类型信息,因此您只能逐个尝试,@ Sachin Gupta的答案将是一个不错的选择。
我想提供一个额外选项:定义一个all-in-one
实体,其中包括MyClass1
,MyClass2
和MyClass3
的所有字段,并生成MyClass1
,MyClass2
和MyClass3
是分开的包装器,只为每个包装器公开相关的字段。代码如下:
班级AllInOne
:
public class AllInOne {
protected String a;
protected String b;
protected String c;
public A asA() {
return new A(this);
}
public B asB() {
return new B(this);
}
public C asC() {
return new C(this);
}
}
班级A
:
public class A {
private AllInOne allInOne;
public A(AllInOne allInOne) {
this.allInOne = allInOne;
}
public String getA() {
return allInOne.a;
}
}
班级B
:
public class B {
private AllInOne allInOne;
public B(AllInOne allInOne) {
this.allInOne = allInOne;
}
public String getB() {
return allInOne.b;
}
}
班级C
:
public class C {
private AllInOne allInOne;
public C(AllInOne allInOne) {
this.allInOne = allInOne;
}
public String getC() {
return allInOne.c;
}
}
测试代码:
public class Main {
public static void main(String[] args) throws IOException {
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY);
String jsonA = "{\"a\":\"a value\"}";
String jsonB = "{\"b\":\"b value\"}";
String jsonC = "{\"c\":\"c value\"}";
needTypeA(om.readValue(jsonA, AllInOne.class).asA());
needTypeB(om.readValue(jsonB, AllInOne.class).asB());
needTypeC(om.readValue(jsonC, AllInOne.class).asC());
}
private static void needTypeA(A a) {
System.out.println(a.getA());
}
private static void needTypeB(B b) {
System.out.println(b.getB());
}
private static void needTypeC(C c) {
System.out.println(c.getC());
}
}
通过这样的实现,我们在反序列化步骤中删除了特定的类型信息,并在我们真正需要/使用它时将其恢复。正如你所看到的,没有太多额外的代码,因为我们实际上只是将所有字段声明一起移动,并添加了几个方法。
注意:
AllInOne
中的字段声明为protected
,将所有POJO类放在同一个包中会使A
,B
和C
能够直接访问它们,但不能访问其他类。om.setVisibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY);
以使field
进行杰克森反序列化,以便我们可以从setter
类getter
和AllInOne
isA
内添加AllInOne
等方法答案 2 :(得分:0)
如果json包含一些define属性,那么您可以尝试使用@JsonTypeInfo
和@JsonSubTypes
。类MyClass1, ...
必须实现此接口。另外,我不记得如何将未知实现映射到null。
@JsonTypeInfo(
use = JsonTypeInfo.Id.NAME,
include = JsonTypeInfo.As.EXISTING_PROPERTY, // level of define property
property = <property_name>,
visible = true,
defaultImpl = NoClass.class)
@JsonSubTypes({@JsonSubTypes.Type(value = <interface-impl>.class, name = <property_value>)})
private <interface> value;
// getters and setters