使用后代元素解析JSON列表

时间:2016-04-20 06:07:54

标签: java json jackson polymorphism deserialization

有一个函数可以返回JSON格式的元素列表。从包含后代类型元素的结果中读取内容时会出现问题。

例如,请考虑以下定义:

public class Fruits {
    public String description;
    public List<Fruit> fruits = new ArrayList<Fruit>();
}

public class Fruit {
    public String name;
    public int pieces;
}

public class Banana extends Fruit {
    public String origin;
}


@ApplicationScoped
@Provider
@Produces("application/json")
@Path("/fruit")
public class MyRestService {
    @GET
    @Path("/fruits")
    public Fruits getFruits() {
        Fruits myFruits = new Fruits();
        myFruits.description = "My fruits";

        Fruit myApple = new Fruit();
        myApple.name = "apple";
        myApple.pieces = 8;
        myFruits.fruits.add(myApple);

        Banana myBanana = new Banana();
        myBanana.name = "banana";
        myBanana.pieces = 5;
        myBanana.origin = "Ecuador";
        myFruits.fruits.add(myBanana);

        return myFruits;
    }
}

生成的JSON如下:

{  
   "description":"My fruits",
   "fruits":[  
      {  
         "name":"apple",
         "pieces":8
      },
      {  
         "name":"banana",
         "pieces":5,
         "origin":"Ecuador"
      }
   ]
}

假设我们在content变量中得到了这个结果。我想按如下方式解析它:

ObjectMapper objectMapper = new ObjectMapper();
Fruits fruits = objectMapper.readValue(content, Fruits.class);

抛出以下异常:

Exception in thread "main" org.codehaus.jackson.map.exc.UnrecognizedPropertyException: Unrecognized field "origin" (Class myresttest.Fruit), not marked as ignorable
 at [Source: java.io.StringReader@38653ad5; line: 1, column: 104] (through reference chain: myresttest.Fruits["fruits"]->myresttest.Fruit["origin"])

是否有可能在不触及服务器代码的情况下克服此问题?

2 个答案:

答案 0 :(得分:2)

我建议您使用 json-simple-1.1.1

你可以像这样得到JSonObject:

JSONObjec requestobj = (JSONObject) JSonValue.parse(request) ;
  

注意:请求值应该是JSON的String表示形式。

然后将requestobj字段解析为新的Fruits实例... 例如:

Fruits myFruits = new Fruits();

myFruits.description = (String) requestobj.getString("description");

答案 1 :(得分:1)

首先,我相信你使用的是杰克逊的旧版本。至少在三年前,org.codehaus.jacksoncom.fasterxml.jackson感动了。你仍然可以使用它,但我建议使用支持的版本(如果可能的话)。

当你定义List Jackson时,问题并不知道任何关于Fruit的任何子类的问题。要通知Jackson这个类有子类,而你不想从它们中删除数据,你需要添加@JsonTypeInfo和@JsonSubTypes。

class Fruits {
    public String description;
    public List<Fruit> fruits = new ArrayList<Fruit>();
}

@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "type", defaultImpl = Fruit.class)
@JsonSubTypes({@JsonSubTypes.Type(value = Fruit.class, name = "fruit"),
        @JsonSubTypes.Type(value = Banana.class, name = "banana")})
class Fruit {
    public String name;
    public int pieces;
}

class Banana extends Fruit {
    public String origin;
}

请注意,它会将生成的JSON更改为:

{
  "description": "My fruits",
  "fruits": [
    {
      "type": "fruit",
      "name": "apple",
      "pieces": 8
    },
    {
      "type": "banana",
      "name": "banana",
      "pieces": 5,
      "origin": "Ecuador"
    }
  ]
}

请注意,此JSON现在有一个额外的字段type,Jackson将使用它来确定需要使用哪个子类来反序列化JSON。

您可以更改此属性名称以及Jackson如何将额外信息包含到JSON中。您可以在此处详细了解:http://fasterxml.github.io/jackson-annotations/javadoc/2.4/com/fasterxml/jackson/annotation/JsonTypeInfo.html?is-external=true