2014-01-06 101 views
3

我试图从JSON中将一些MediaWiki上下文反序列化为使用Jackson进入POJO。但是,问题在于其中一个JSON对象名称是文章的整数ID值,因此不能使用像@JsonProperty这样的注释,因为该值永远不会保持不变。使用Jackson解析动态生成的JSON对象名称

下面是一些示例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建议添加& indexpageids参数,以协助解析,但我看不出它如何将有用)

我试着使用@JsonAnyGetter@JsonAnySetter注释,但它们似乎没有帮助,抛出同样的异常com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: Unrecognized field "736" (class WikipediaPages), not marked as ignorable (one known property: "wikipediaPage"])

感谢您的任何和所有帮助。

编辑:下面是相关类看起来像此刻什么:

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

我使用的是杰克逊的Mixin应用注释:

public interface WikipediaPagesMixIn { 

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

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

编辑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(); 
} 
+1

使'页面'为'Map '其中'页面包含所有其他数据。 –

+0

同样的例外:'com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException:无法识别的字段“38991692”(class WikipediaPages),未标记为可忽略(一个已知属性:“wikipediaPageMap”])''。 –

+0

向我们显示您的代码。 –

回答

2

要回答您的例外的根本原因,@JsonAnySetter javadoc状态

标记注释可以用于定义非静态, 两个参数方法(的属性的第一个参数的名称,第二值 集),[...]

因此,使用像这样的mixin

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

未注册它,因此未找到该属性。

老实说,如果你控制数据类,不要使用mixins。您可以直接映射这些字段,如下所示。


我不知道你是如何使用您的混入,但对我来说,以下工作

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); 

打印

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

哪里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; 
    } 
} 

剩下的就是将Map<String, Page>作为字段放在querypages JSON元素的某些包装类中。

+0

如果我使用顶层的代码块,它也可以。我通过创建一个Jackson模块来应用mixin,在'setupContext'方法中添加每个mixin,并在'ObjectMapper'实例化中应用模块。我想保持与我的JSON反序列化代码的其余部分保持一致,然后解决原始问题。 –

+0

@ryan据我所知,错误发生是因为Jackson不知道如何映射JSON元素名称'736'。没有看到你是如何做你的反序列化,我不禁感慨。 –

+0

我有4个模型类,用于顶级JSON的WikipediaResult,用于“查询”对象的WikipediaQuery,用于“页面”对象的维基百科页面和用于动态命名对象的维基百科页面。我通过调用'WikipediaResult wikipediaResult = JacksonBuilder.getObjectMapper()。readValue(getInputStreamFromConnection(buildURLFromQuery(query)),WikipediaResult.class)'来进行反序列化。从HTTP连接提供一个InputStream。 JacksonBuilder只是实例化一个新的ObjectMapper实例,并将包含mixin的模块添加到它。 –