【问题标题】:How to replace null fields (nested at all levels) from JSON response using Jackson ObjectMapper serialization?如何使用 Jackson ObjectMapper 序列化从 JSON 响应中替换空字段(嵌套在所有级别)?
【发布时间】:2015-06-26 18:21:31
【问题描述】:

我正在使用以下代码以 JSON 响应的形式从 Twitter4j 搜索 API 接收推文。我收到的结果是以列表形式在 Twitter4j 搜索 API 中指定的行

List<Status> tweets = result.getTweets();

问题是推文以列表形式返回,其中一个状态条目具有非空和非空地理位置,而另一个状态条目具有空或空地理位置。因为要从每个状态条目(即 Tweet)中检索相关字段,所以我遍历列表并调用 getter,这对于 GeoLocation 字段为空的状态条目来说是空的。

我尝试遵循的方法:

我创建了一个 POJO TweetJSON_2(在帖子底部定义),其中包含相关字段及其 getter 和 setter。我正在使用 Jackson ObjectMapper 来处理空值,如下所示:

    JsonGenerator generator = new JsonFactory().createGenerator(os);
                    generator.setPrettyPrinter(new DefaultPrettyPrinter());
                    TweetJSON_2 rawJSON; 

                    ObjectMapper mapper = new ObjectMapper();
                    //mapper.setVisibility(PropertyAccessor.FIELD, Visibility.ANY);
                    mapper.configure(SerializationFeature.WRITE_NULL_MAP_VALUES, false);
                    mapper.setSerializationInclusion(Include.NON_NULL);
// ... rawJSON is populated ...
    mapper.writeValue(generator, rawJSON);

但是,当我尝试从 Status 中获取 geoLocation 字段时,使用下面标有 ** 的行

List<Status> tweets = result.getTweets();

我得到的 Java NullPointerException 如下:

[Mon Apr 20 11:32:47 IST 2015]{"statuses":[{"retweeted_status":{"contributors":null,"text":"<my text>",**"geo":null**,"retweeted":false,"in_reply_to_screen_name":null,"truncated":false,"lang":"en","entities":{"symbols":[],"urls":[],"hashtags": ... &include_entities=1","since_id_str":"0","completed_in":0.029}}

    **Exception in thread "main" java.lang.NullPointerException
        at analytics.search.twitter.SearchFieldsTweetsJSON_2.main(SearchFieldsTweetsJSON_2.java:78)**

例如:如果我输入一个json字符串为

String s = "{\"first\": 123, \"second\": [{\"second_first\":null, \"second_second\":null}, {\"second_third\":null}, null], \"third\": 789, \"fourth\":null}";

输出应该是这样的

"{\"first\": 123, \"third\": 789}";

我想要的是替换 JSONArrays 中的所有 null 元素和 JSONObjects 中的所有 null 键值对,无论它们嵌套在我的 JSON 响应中的任何级别。

对象与树模型方法

我尝试了对象模型解析机制,它是一个基于 javax.json.stream.JsonParser.Event 的方法,但需要对 JSON 字符串进行多次访问和对象替换,具体取决于 null 嵌套在哪个级别上非常复杂。同时,如果我使用树模型机制,整个 JSON 响应必须存储为树,这可能会溢出我的 JVM 堆内存,因为根据我的查询参数,JSON 大小可能非常大。我需要找到一个可行的解决方案来克服这个问题。任何有关解决上述问题的建议都将受到高度赞赏。

代码如下:

public class SearchFieldsTweetsJSON_2 {
    /* Searches specific fields from Tweets in JSON format */

    public static void main(String[] args) throws FileNotFoundException, IOException {
        if (args.length < 2) {
            System.out.println("java twitter4j.examples.search.SearchTweets [query][outputJSONFile]");
            System.exit(-1);
        }
        ConfigurationBuilder cb = new ConfigurationBuilder();
        cb.setDebugEnabled(true)
        .setOAuthConsumerKey("XXXXXXXXXXXXXXXXXXXXXXXXXX")
        .setOAuthConsumerSecret("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX")
        .setOAuthAccessToken("NNNNNNNNN-XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX")
        .setOAuthAccessTokenSecret("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX")
        .setJSONStoreEnabled(true);
        Twitter twitter = new TwitterFactory(cb.build()).getInstance(); 
        try {
            Query query = new Query(args[0]);
            QueryResult result;
            File jsonFile = new File(args[1]);
            System.out.println("File Path : " + jsonFile.getAbsolutePath());
            OutputStreamWriter os = new OutputStreamWriter(new FileOutputStream(jsonFile));

            JsonGenerator generator = new JsonFactory().createGenerator(os);
            generator.setPrettyPrinter(new DefaultPrettyPrinter());
            TweetJSON_2 rawJSON; 

            ObjectMapper mapper = new ObjectMapper();
            //mapper.setVisibility(PropertyAccessor.FIELD, Visibility.ANY);
            mapper.configure(SerializationFeature.WRITE_NULL_MAP_VALUES, false);
            mapper.setSerializationInclusion(Include.NON_NULL);

            do {
                result = twitter.search(query);
                List<Status> tweets = result.getTweets();
                for (Status tweet : tweets) {
                    rawJSON = new TweetJSON_2();
                    rawJSON.setStatusId(Long.toString(tweet.getId()));
                    rawJSON.setUserId(Long.toString(tweet.getUser().getId()));
                    rawJSON.setUserName(tweet.getUser().getScreenName());
                    rawJSON.setStatusText(tweet.getText());
                    rawJSON.setGeoLocation(tweet.getGeoLocation().toString()); **<< Giving error at tweet.getGeoLocation() since GeoLocation is null**
                    mapper.writeValue(generator, rawJSON);
                    System.out.println(rawJSON.toString());
                }
            } while ((query = result.nextQuery()) != null); 
            generator.close();
            System.out.println(os.toString());
        } catch (TwitterException te) {
            te.printStackTrace();
            System.out.println("Failed to search tweets : " + te.getMessage());
            System.exit(-1);
        } 
    }

}

我已按如下方式定义了我的 TweetJSON_2 Java 对象:

public class TweetJSON_2 {

    public  String statusId;
    public  String statusText;
    public  String userId;
    public  String userName;
    public  String geoLocation;

    public String getStatusId() {
        return statusId;
    }
    public void setStatusId(String statusId) {
        this.statusId = statusId;
    }
    public String getStatusText() {
        return statusText;
    }
    public void setStatusText(String statusText) {
        this.statusText = statusText;
    }
    public String getUserId() {
        return userId;
    }
    public void setUserId(String userId) {
        this.userId = userId;
    }
    public String getUserName() {
        return userName;
    }
    public void setUserName(String userName) {
        this.userName = userName;
    }
    public String getGeoLocation() {
        return geoLocation;
    }
    public void setGeoLocation(String geoLocation) {
        this.geoLocation = geoLocation;
    }
    @Override
    public String toString() {
        return "TweetJSON_2 [ statusId = " + statusId + ", statusText = " + statusText + "]";
    }
}

【问题讨论】:

    标签: json serialization jackson twitter4j pojo


    【解决方案1】:

    我尝试用以下方式重新配置我的 POJO,它成功替换了 setter 方法中指定的所有空值。不需要遵循 JSON 字符串的树或基于事件的模型解析。高温

    修改后的 TweetJSON_2 POJO:

    public class TweetJSON_2 {
        public  Long statusId = null;
        public  String statusText = null;
        public  Long userId = null;
        public  String userName = null;
        public  GeoLocation geoLocation = null;
    
        public Long getStatusId() {
            if (this.statusId==null)
                return new Long(0L);
            return statusId;
        }
        public void setStatusId(Long statusId) {
            if (statusId==null)
                this.statusId = new Long(0L);
            else
                this.statusId = statusId;
        }
        public String getStatusText() {
            if (this.statusText==null)
                return new String("");
            return statusText;
        }
        public void setStatusText(String statusText) {
            if (statusText==null)
                this.statusText = new String("");
            else
                this.statusText = statusText;
        }
        public Long getUserId() {
            if (this.userId==null)
                return new Long(0L);
            return userId;
        }
        public void setUserId(Long userId) {
            if (userId==null)
                this.userId = new Long(0L);
            else
                this.userId = userId;
        }
        public String getUserName() {
            if (this.userName==null)
                return new String("");
            return userName;
        }
        public void setUserName(String userName) {
            if (userName==null)
                this.userName = new String("");
            else
                this.userName = userName;
        }
        public GeoLocation getGeoLocation() {
            if (this.geoLocation==null)
                return new GeoLocation(0.0,0.0);
            return geoLocation;
        }
        public void setGeoLocation(GeoLocation geoLocation) {
            if (geoLocation==null)
                this.geoLocation = new GeoLocation(0.0,0.0);
            else
                this.geoLocation = geoLocation;
        }
        @Override
        public String toString() {
            return "TweetJSON_2 [ statusId = " + statusId + ", statusText = " + statusText + "]";
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2016-10-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-02-13
      • 1970-01-01
      • 1970-01-01
      • 2019-10-31
      相关资源
      最近更新 更多