2017-04-05 23 views
0

我在我的应用程序中使用了Jackson的de/serialization。Fallback类<?> for mapper.readValue

我有一种情况,我需要将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块?

回答

1

你可以试试这个方法来做反序列化的事情。这将在UnrecognizedPropertyException返回null

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; 
    } 
+0

谢谢你的回答。但似乎忽略未知属性的配置只是通过'Class '创建一个提供的类的空实例,并使用默认值,而不是创建类的null实例。希望这个解释清楚。 –

+1

我已经更新了我的答案,您可以创建一个通用的方法来做这种事情。 –

0

如果jsonString由您生成,可以考虑添加type info,然后用它来转换反序列化对象。您可以参考this post了解如何操作。

如果jsonString由您无法控制的其他服务生成,那么您无法获得任何类型信息,因此您只能一个接一个地尝试,@Sachin Gupta的答案将是一个不错的选择。

我想提供一个额外的选项:定义一​​个all-in-one实体包括MyClass1MyClass2MyClass3各个领域,使MyClass1MyClass2MyClass3分开包装,只露出每个相关领域。代码如下:

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类在同一个包将使ABC能够直接访问它们,而不是外部的其他类。
  • 设置om.setVisibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY);,使杰克逊的field反序列化,这样我们就可以从AllInOne
  • 删除重复settergetter如果你需要知道是什么类型的信息,您可以添加方法,如isAAllInOne基础上的字段信息
0

如果json包含一些定义属性,那么您可以尝试使用@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 
相关问题