JAX-RS/Jackson——反序列化根元素名称未知的JSON?

JAX-RS/Jackson——反序列化根元素名称未知的JSON?,json,jaxb,jackson,jax-rs,resteasy,Json,Jaxb,Jackson,Jax Rs,Resteasy,我正在编写一个RESTeasy代理客户端,用于检索iTunes类别列表。当您查询有关给定类别的信息时,例如使用此URL: https://itunes.apple.com/WebObjects/MZStoreServices.woa/ws/genres?id=1420 …您得到的JSON响应如下所示: { "1420":{ "name":"Self-Help", "id":"1420", "url":"https://itunes.apple.

我正在编写一个RESTeasy代理客户端,用于检索iTunes类别列表。当您查询有关给定类别的信息时,例如使用此URL:

https://itunes.apple.com/WebObjects/MZStoreServices.woa/ws/genres?id=1420
…您得到的JSON响应如下所示:

{  
   "1420":{  
      "name":"Self-Help",
      "id":"1420",
      "url":"https://itunes.apple.com/us/genre/podcasts-health-self-help/id1420?mt=2",
      "rssUrls":{  
         "topVideoPodcastEpisodes":"https://itunes.apple.com/us/rss/topvideopodcastepisodes/genre=1420/json",
         "topAudioPodcasts":"https://itunes.apple.com/us/rss/topaudiopodcasts/genre=1420/json",
         "topVideoPodcasts":"https://itunes.apple.com/us/rss/topvideopodcasts/genre=1420/json",
         "topPodcasts":"https://itunes.apple.com/us/rss/toppodcasts/genre=1420/json",
         "topAudioPodcastEpisodes":"https://itunes.apple.com/us/rss/topaudiopodcastepisodes/genre=1420/json",
         "topPodcastEpisodes":"https://itunes.apple.com/us/rss/toppodcastepisodes/genre=1420/json"
      },
      "chartUrls":{  
         "videoPodcastEpisodes":"https://itunes.apple.com/WebObjects/MZStoreServices.woa/ws/charts?cc=us&g=1420&name=VideoPodcastEpisodes",
         "podcasts":"https://itunes.apple.com/WebObjects/MZStoreServices.woa/ws/charts?cc=us&g=1420&name=Podcasts",
         "audioPodcastEpisodes":"https://itunes.apple.com/WebObjects/MZStoreServices.woa/ws/charts?cc=us&g=1420&name=AudioPodcastEpisodes",
         "audioPodcasts":"https://itunes.apple.com/WebObjects/MZStoreServices.woa/ws/charts?cc=us&g=1420&name=AudioPodcasts",
         "podcastEpisodes":"https://itunes.apple.com/WebObjects/MZStoreServices.woa/ws/charts?cc=us&g=1420&name=PodcastEpisodes",
         "videoPodcasts":"https://itunes.apple.com/WebObjects/MZStoreServices.woa/ws/charts?cc=us&g=1420&name=VideoPodcasts"
      }
   }
}
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class ITunesCategory implements TransferObject {

    private static final long serialVersionUID = 3443545925023804457L;

    @XmlElement(name = "id")
    @JsonProperty("id")
    private String identifier = null;

    @XmlElement
    private String name = null;

    @XmlElementWrapper(name = "subgenres")
    private List<ITunesCategory> subcategories = new ArrayList<ITunesCategory>();

    ...
}
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class ITunesCategoryList implements TransferObject {

    private static final long serialVersionUID = 3303125979016445238L;

    @XmlElement
    private List<ITunesCategory> categories = new ArrayList<ITunesCategory>();

    ...
}
我试图使用JAXB和Jackson将此JSON响应映射到Java对象。但是,“1420”根元素名称似乎导致了一个问题,因为我在调用客户端时遇到以下异常:

Unrecognized field "1420" (class foo.bar.ITunesCategoryList), not marked as ignorable
我的JAXB类如下所示:

{  
   "1420":{  
      "name":"Self-Help",
      "id":"1420",
      "url":"https://itunes.apple.com/us/genre/podcasts-health-self-help/id1420?mt=2",
      "rssUrls":{  
         "topVideoPodcastEpisodes":"https://itunes.apple.com/us/rss/topvideopodcastepisodes/genre=1420/json",
         "topAudioPodcasts":"https://itunes.apple.com/us/rss/topaudiopodcasts/genre=1420/json",
         "topVideoPodcasts":"https://itunes.apple.com/us/rss/topvideopodcasts/genre=1420/json",
         "topPodcasts":"https://itunes.apple.com/us/rss/toppodcasts/genre=1420/json",
         "topAudioPodcastEpisodes":"https://itunes.apple.com/us/rss/topaudiopodcastepisodes/genre=1420/json",
         "topPodcastEpisodes":"https://itunes.apple.com/us/rss/toppodcastepisodes/genre=1420/json"
      },
      "chartUrls":{  
         "videoPodcastEpisodes":"https://itunes.apple.com/WebObjects/MZStoreServices.woa/ws/charts?cc=us&g=1420&name=VideoPodcastEpisodes",
         "podcasts":"https://itunes.apple.com/WebObjects/MZStoreServices.woa/ws/charts?cc=us&g=1420&name=Podcasts",
         "audioPodcastEpisodes":"https://itunes.apple.com/WebObjects/MZStoreServices.woa/ws/charts?cc=us&g=1420&name=AudioPodcastEpisodes",
         "audioPodcasts":"https://itunes.apple.com/WebObjects/MZStoreServices.woa/ws/charts?cc=us&g=1420&name=AudioPodcasts",
         "podcastEpisodes":"https://itunes.apple.com/WebObjects/MZStoreServices.woa/ws/charts?cc=us&g=1420&name=PodcastEpisodes",
         "videoPodcasts":"https://itunes.apple.com/WebObjects/MZStoreServices.woa/ws/charts?cc=us&g=1420&name=VideoPodcasts"
      }
   }
}
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class ITunesCategory implements TransferObject {

    private static final long serialVersionUID = 3443545925023804457L;

    @XmlElement(name = "id")
    @JsonProperty("id")
    private String identifier = null;

    @XmlElement
    private String name = null;

    @XmlElementWrapper(name = "subgenres")
    private List<ITunesCategory> subcategories = new ArrayList<ITunesCategory>();

    ...
}
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class ITunesCategoryList implements TransferObject {

    private static final long serialVersionUID = 3303125979016445238L;

    @XmlElement
    private List<ITunesCategory> categories = new ArrayList<ITunesCategory>();

    ...
}
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
公共类ITunesCategory实现了TransferObject{
私有静态最终长serialVersionUID=3443545925023804457L;
@xmlement(name=“id”)
@JsonProperty(“id”)
私有字符串标识符=null;
@XmlElement
私有字符串名称=null;
@XmlElementWrapper(name=“subgenres”)
私有列表子类别=新建ArrayList();
...
}
我甚至尝试创建一个包装类,因为搜索可能会返回多个类别。看起来是这样的:

{  
   "1420":{  
      "name":"Self-Help",
      "id":"1420",
      "url":"https://itunes.apple.com/us/genre/podcasts-health-self-help/id1420?mt=2",
      "rssUrls":{  
         "topVideoPodcastEpisodes":"https://itunes.apple.com/us/rss/topvideopodcastepisodes/genre=1420/json",
         "topAudioPodcasts":"https://itunes.apple.com/us/rss/topaudiopodcasts/genre=1420/json",
         "topVideoPodcasts":"https://itunes.apple.com/us/rss/topvideopodcasts/genre=1420/json",
         "topPodcasts":"https://itunes.apple.com/us/rss/toppodcasts/genre=1420/json",
         "topAudioPodcastEpisodes":"https://itunes.apple.com/us/rss/topaudiopodcastepisodes/genre=1420/json",
         "topPodcastEpisodes":"https://itunes.apple.com/us/rss/toppodcastepisodes/genre=1420/json"
      },
      "chartUrls":{  
         "videoPodcastEpisodes":"https://itunes.apple.com/WebObjects/MZStoreServices.woa/ws/charts?cc=us&g=1420&name=VideoPodcastEpisodes",
         "podcasts":"https://itunes.apple.com/WebObjects/MZStoreServices.woa/ws/charts?cc=us&g=1420&name=Podcasts",
         "audioPodcastEpisodes":"https://itunes.apple.com/WebObjects/MZStoreServices.woa/ws/charts?cc=us&g=1420&name=AudioPodcastEpisodes",
         "audioPodcasts":"https://itunes.apple.com/WebObjects/MZStoreServices.woa/ws/charts?cc=us&g=1420&name=AudioPodcasts",
         "podcastEpisodes":"https://itunes.apple.com/WebObjects/MZStoreServices.woa/ws/charts?cc=us&g=1420&name=PodcastEpisodes",
         "videoPodcasts":"https://itunes.apple.com/WebObjects/MZStoreServices.woa/ws/charts?cc=us&g=1420&name=VideoPodcasts"
      }
   }
}
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class ITunesCategory implements TransferObject {

    private static final long serialVersionUID = 3443545925023804457L;

    @XmlElement(name = "id")
    @JsonProperty("id")
    private String identifier = null;

    @XmlElement
    private String name = null;

    @XmlElementWrapper(name = "subgenres")
    private List<ITunesCategory> subcategories = new ArrayList<ITunesCategory>();

    ...
}
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class ITunesCategoryList implements TransferObject {

    private static final long serialVersionUID = 3303125979016445238L;

    @XmlElement
    private List<ITunesCategory> categories = new ArrayList<ITunesCategory>();

    ...
}
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
公共类ITunesCategoryList实现TransferObject{
私有静态最终长serialVersionUID=330312597909016445238L;
@XmlElement
私有列表类别=新的ArrayList();
...
}
但是,无论我指定哪个类作为返回类型,我都会得到相同的错误,因为类别标识符是JSON对象的根元素名


有没有办法告诉JAXB/Jackson/JAX-RS/RESTeasy忽略根元素名,只将底层对象映射到Java?我无法在开发/编译时知道根元素名称,因为它直接对应于搜索返回的结果。有什么办法可以绕过这个异常吗?谢谢你能给我的帮助

我找不到太多关于动态忽略根的内容,至少没有任何适合JAX-RS环境的内容。我唯一能想到的就是编写一个自定义反序列化程序,然后跳过根节点。差不多

import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.IOException;
import java.util.Map;

public abstract class IHateRootElemsJsonDeserializer<T> extends JsonDeserializer<T> {

    private final ObjectMapper mapper = new ObjectMapper();
    private final Class<T> cls;

    public IHateRootElemsJsonDeserializer(Class<T> cls) {
        this.cls = cls;
    }

    @Override
    public T deserialize(JsonParser jp, DeserializationContext dc) 
            throws IOException, JsonProcessingException {
       JsonNode rootNode = jp.getCodec().readTree(jp);
       Map.Entry<String,JsonNode> field = rootNode.fields().next();
       JsonNode node = field.getValue();
       T result = mapper.convertValue(node, cls);
       return result;
    }  
}
模型

public class Genre {

    public String id;
    public String name;
    public String url;
    public RssUrls rssUrls;
    public ChartUrls chartUrls;

    @Override
    public String toString() {
        return "Category{" + "id=" + id + ", name=" 
                + name + ", url=" + url + ", rssUrls=" + rssUrls + '}';
    }

    public static class RssUrls {
        public String topVideoPodcastEpisodes;
        public String topAudioPodcasts;
        public String topVideoPodcasts;
        public String topPodcasts;
        public String topAudioPodcastEpisodes;
        public String topPodcastEpisodes;

        @Override
        public String toString() {
            return "RssUrls{" + "topVideoPodcastEpisodes=" + topVideoPodcastEpisodes 
                    + ", topAudioPodcasts=" + topAudioPodcasts 
                    + ", topVideoPodcasts=" + topVideoPodcasts 
                    + ", topPodcasts=" + topPodcasts 
                    + ", topAudioPodcastEpisodes=" + topAudioPodcastEpisodes 
                    + ", topPodcastEpisodes=" + topPodcastEpisodes + '}';
        }

    }

    public static class ChartUrls {
        public String videoPodcastEpisodes;
        public String podcasts;
        public String audioPodcastEpisodes;
        public String audioPodcasts;
        public String podcastEpisodes;
        public String videoPodcasts;

        @Override
        public String toString() {
            return "ChatUrls{" + "videoPodcastEpisodes=" + videoPodcastEpisodes 
                    + ", podcasts=" + podcasts 
                    + ", audioPodcastEpisodes=" + audioPodcastEpisodes 
                    + ", audioPodcasts=" + audioPodcasts 
                    + ", podcastEpisodes=" + podcastEpisodes
                    + ", videoPodcasts=" + videoPodcasts + '}';
        }   
    }
}

要在JAX-RS中配置
ObjectMapper
,您可以查看谢谢!我一定会看一看,然后试一试!工作得很有魅力!谢谢