简体   繁体   English

使用Jackson解析动态生成的JSON对象名称

[英]Parsing dynamically generated JSON object names with Jackson

I'm attempting to deserialize some MediaWiki context from JSON using Jackson into POJOs. 我正在尝试使用Jackson将一些MediaWiki上下文从JSON反序列化为POJO。 However, the problem is that one of the JSON object names is the integer ID value of the article, so using an annotation like @JsonProperty can't be used because the value is never constant. 但是,问题是其中一个JSON对象名是文章的整数ID值,因此不能使用像@JsonProperty这样的注释,因为该值永远不会是常量。

Here's some sample JSON to describe what I mean: 这里有一些示例JSON来描述我的意思:

http://en.wikipedia.org/w/api.php?action=query&titles=Albert%20Einstein&prop=info&format=json&indexpageids

{
    "query": {
        "pageids": [
            "736"
        ],
        "pages": {
            "736": {
                "pageid": 736,
                "ns": 0,
                "title": "Albert Einstein",
                "contentmodel": "wikitext",
                "pagelanguage": "en",
                "touched": "2014-01-05T03:14:23Z",
                "lastrevid": 588780054,
                "counter": "",
                "length": 106159
            }
        }
    }
}

(MediaWiki recommends adding the &indexpageids parameter to assist with parsing, however I can't see how it would be useful to me.) (MediaWiki建议添加&indexpageids参数来帮助解析,但我看不出它对我有用。)

I tried using the @JsonAnyGetter and @JsonAnySetter annotations as well but they don't appear to help, throwing the same exception com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: Unrecognized field "736" (class WikipediaPages), not marked as ignorable (one known property: "wikipediaPage"]) . 我尝试使用@JsonAnyGetter@JsonAnySetter注释,但它们似乎没有帮助,抛出相同的异常com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: Unrecognized field "736" (class WikipediaPages), not marked as ignorable (one known property: "wikipediaPage"])

Thanks for any and all assistance. 感谢您的任何和所有帮助。

Edit: Here's what the relevant classes look like at the moment: 编辑:这是相关课程目前的样子:

public class WikipediaPages {

    private Map<String, WikipediaPage> wikipediaPageMap = new HashMap<String, WikipediaPage>();

    public Map<String, WikipediaPage> getWikipediaPageMap() {
        return wikipediaPageMap;
    }

    public void setWikipediaPageMap(Map<String, WikipediaPage> wikipediaPageMap) {
        this.wikipediaPageMap = wikipediaPageMap;
    }
}

I use a Jackson Mixin to apply annotations: 我使用Jackson Mixin来应用注释:

public interface WikipediaPagesMixIn {

    @JsonAnyGetter
    Map<String, WikipediaPage> getWikipediaPageMap();

    @JsonAnySetter
    void setWikipediaPageMap(Map<String, WikipediaPage> wikipediaPageMap);
}

Edit 2: More code, as requested: 编辑2:根据要求提供更多代码:

public class JacksonBuilder {

    private static ObjectMapper objectMapper;

    public static ObjectMapper getObjectMapper() {
        if(objectMapper == null) {
            objectMapper = new ObjectMapper();
            objectMapper.registerModule(new WikipediaModule());
        }

        return objectMapper;
    }
}

public class WikipediaModule extends SimpleModule {

    public WikipediaModule() {
        super("WikipediaModule", new Version(1, 0, 0, null, "net.ryanmorrison", "sentience"));
    }

    @Override
    public void setupModule(SetupContext setupContext) {
        setupContext.setMixInAnnotations(WikipediaPage.class, WikipediaPageMixIn.class);
        setupContext.setMixInAnnotations(WikipediaPages.class, WikipediaPagesMixIn.class);
        setupContext.setMixInAnnotations(WikipediaQuery.class, WikipediaQueryMixIn.class);
        setupContext.setMixInAnnotations(WikipediaResult.class, WikipediaResultMixIn.class);
    }
}

public class WikipediaResult {

    private WikipediaQuery wikipediaQuery;

    public WikipediaQuery getWikipediaQuery() {
        return wikipediaQuery;
    }

    public void setWikipediaQuery(WikipediaQuery wikipediaQuery) {
        this.wikipediaQuery = wikipediaQuery;
    }
}

public interface WikipediaResultMixIn {

    @JsonProperty("query")
    WikipediaQuery getWikipediaQuery();
}

To answer the root cause of your exception, the @JsonAnySetter javadoc states 为了回答异常的根本原因, @JsonAnySetter javadoc指出

Marker annotation that can be used to define a non-static, two-argument method (first argument name of property, second value to set) , [...] 标记注释,可用于定义非静态, 双参数方法(属性的第一个参数名称,要设置的第二个值) ,[...]

As such, using a mixin like this 因此,使用像这样的mixin

@JsonAnySetter
void setWikipediaPageMap(Map<String, WikipediaPage> wikipediaPageMap);

doesn't register it and therefore the property isn't found. 没有注册,因此找不到该属性。

Honestly, don't use mixins if you control the data classes. 老实说,如果你控制数据类,不要使用mixins。 You can directly map the fields as I've shown below. 您可以直接映射字段,如下所示。


I don't know how you are using your mixin, but the following works for me 我不知道你是如何使用mixin的,但以下内容对我有用

String json = "{ \"query\": { \"pageids\": [ \"736\" ], \"pages\": { \"736\": { \"pageid\": 736, \"ns\": 0, \"title\": \"Albert Einstein\", \"contentmodel\": \"wikitext\", \"pagelanguage\": \"en\", \"touched\": \"2014-01-05T03:14:23Z\", \"lastrevid\": 588780054, \"counter\": \"\", \"length\": 106159 } } } }";
ObjectMapper mapper = new ObjectMapper();
JsonNode node =mapper.readTree(json);

node = node.get("query").get("pages");

Map<String, Page> pages = mapper.readValue(node.traverse(), new TypeReference<Map<String, Page>>() {
});

System.out.println(pages);

prints 版画

{736=Page [pageid=736, ns=0, title=Albert Einstein, contentmodel=wikitext, pagelanguage=en, touched=2014-01-05T03:14:23Z, lastrevid=588780054, counter=, length=106159]}

Where Page is Page是哪里的

class Page {
    private int pageid;
    private int ns;
    private String title;
    private String contentmodel;
    private String pagelanguage;
    private String touched; // this could be a Date, with the appropriate format configuration
    private int lastrevid;
    private String counter;
    private int length;
    @Override
    public String toString() {
        return "Page [pageid=" + pageid + ", ns=" + ns + ", title=" + title
                + ", contentmodel=" + contentmodel + ", pagelanguage="
                + pagelanguage + ", touched=" + touched + ", lastrevid="
                + lastrevid + ", counter=" + counter + ", length=" + length
                + "]";
    }
    public int getPageid() {
        return pageid;
    }
    public void setPageid(int pageid) {
        this.pageid = pageid;
    }
    public int getNs() {
        return ns;
    }
    public void setNs(int ns) {
        this.ns = ns;
    }
    public String getTitle() {
        return title;
    }
    public void setTitle(String title) {
        this.title = title;
    }
    public String getContentmodel() {
        return contentmodel;
    }
    public void setContentmodel(String contentmodel) {
        this.contentmodel = contentmodel;
    }
    public String getPagelanguage() {
        return pagelanguage;
    }
    public void setPagelanguage(String pagelanguage) {
        this.pagelanguage = pagelanguage;
    }
    public String getTouched() {
        return touched;
    }
    public void setTouched(String touched) {
        this.touched = touched;
    }
    public int getLastrevid() {
        return lastrevid;
    }
    public void setLastrevid(int lastrevid) {
        this.lastrevid = lastrevid;
    }
    public String getCounter() {
        return counter;
    }
    public void setCounter(String counter) {
        this.counter = counter;
    }
    public int getLength() {
        return length;
    }
    public void setLength(int length) {
        this.length = length;
    }
}

All that is left is to put the Map<String, Page> as a field in some wrapper class for the query and pages JSON elements. 剩下的就是将Map<String, Page>作为字段放在querypages JSON元素的某个包装类中。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM