使用 GSON 将字符串转换为 ArrayList<String>

Convert String to ArrayList<String> using GSON

我正在尝试将 JSON 数据反序列化为 POJO。

问题是列表对象以字符串形式出现,而 gson 给出了一个 IllegalStateExceptioState。如何使用 gson 将字符串作为列表解析为 ArrayList?

JSON数据

{
   "report_id":1943,
   "history_id":3302654,
   "project_id":null,
   "owner_emails":"[\"abcd@xyz.com\"]",
   "message":"Array\n(\n    [name] => SOMENAME\n    [age] => 36\n    [gender] => male\n)\n"
}

POJO:

    public class EventData {
    
        private static Gson gson = new Gson();
    
        @SerializedName("report_id")
        public String reportID;
    
        @SerializedName("history_id")
        public String historyID;
    
        @SerializedName("project_id")
        public String projectID;
    
        @SerializedName("owner_emails")
        public ArrayList<String> ownerEmails = new ArrayList<String>();
    
        @SerializedName("message")
        public String message;
    
    
        @SerializedName("title")
        public String title;
    
        public CrawlerNotifiedEventData(){
            this.projectID = "Undefined";
            this.reportID = "Undefined";
            this.historyID = "Undefined";
            this.title = "";
        }
    
        public String toJson(boolean base64Encode) throws java.io.UnsupportedEncodingException{
            
            String json = gson.toJson(this, CrawlerNotifiedEventData.class);
            
            if(base64Encode)
                return Base64.getEncoder().encodeToString(json.getBytes("UTF8"));
    
            return json;
        }
    
        public String toJson() throws java.io.UnsupportedEncodingException{
            return this.toJson(false);
        }
    
        public static EventData builder(String json){
            return gson.fromJson(json, EventData.class);   
        }
    }

反序列化:

EventData eventData = EventData.builder(json);

反序列化时出现以下错误

com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected BEGIN_ARRAY but was STRING at line 1 column 252 path $.owner_emails

在字符串中装箱不必要的结构化数据是跨不同序列化方法的一个非常常见的设计问题。幸运的是,Gson 可以处理像 owner_emails 这样的字段(当然不能处理 message)。

只需创建一个类型适配器工厂,就可以通过替换原始类型并多做一些工作来为特定类型创建类型适配器。适配器应该将有效负载读取为字符串,并将字符串反序列化委托给它替代的类型适配器。

public final class JsonStringBoxTypeAdapterFactory
        implements TypeAdapterFactory {

    private JsonStringBoxTypeAdapterFactory() {
    }

    @Override
    public <T> TypeAdapter<T> create(final Gson gson, final TypeToken<T> typeToken) {
        final TypeAdapter<T> adapter = gson.getAdapter(typeToken);
        return new TypeAdapter<T>() {
            @Override
            public void write(final JsonWriter out, final T value) {
                throw new UnsupportedOperationException(); // TODO
            }

            @Override
            public T read(final JsonReader in)
                    throws IOException {
                return adapter.fromJson(in.nextString());
            }
        };
    }

}
@AllArgsConstructor
@ToString
@EqualsAndHashCode
final class EventData {

    @SerializedName("owner_emails")
    @JsonAdapter(JsonStringBoxTypeAdapterFactory.class)
    List<String> ownerEmails;

}

下面的单元测试将为绿色:

final EventData eventData = gson.fromJson(json, EventData.class);
Assertions.assertEquals(new EventData(ImmutableList.of("abcd@xyz.com")), eventData);

就是这样。

"owner_emails" 当前是一个字符串如下

"owner_emails":"[\"abcd@xyz.com\"]"

应该是

"owner_emails": ["abcd@xyz.com"]

被视为数组。您可以手动删除引号并对其进行解析。

或者你可以在 Gson

中使用 JsonElement 解析它

您可以使用 jackson library 中的 ObjectMapper 进行此转换。

转换示例代码::

public <T> T mapResource(Object resource, Class<T> clazz) {
        try {
            return objectMapper.readValue(objectMapper.writeValueAsString(resource), clazz);
        } catch (IOException ex) {
            throw new Exception();
        }
    }

修改 list 的模型,如::

 public class Reportdata{
   
   private List<String> owner_emails = new ArrayList(); 

   @JsonDeserialize(contentAs = CustomClass.class)
   private List<CustomClass> customClassList =  new ArrayList();  
   ....// setter and getter
}

除此之外,在创建 ObjectMapper 对象时,您可以传递或注册模块/您的自定义模块以在对象中进行反序列化,如下所示。

objectMapper.setDefaultPropertyInclusion(Include.NON_EMPTY);
objectMapper.disable(SerializationFeature.WRITE_ENUMS_USING_TO_STRING);
objectMapper.registerModule(new JavaTimeModule());