将包含混合类型数组的JSON转换为Java对象

3

我的json字符串看起来像这样:

{
  "text": ["foo",1,"bar","2",3],
  "text1": "value1",
  "ComplexObject": {
   .....
   }
}

我有一个像这样定义的pojo:

class MyPojo {
 List<String> text;
 String text1;
 ComplexObject complexObject;
}

我使用Google Gson,成功地获取了我的Java对象。问题在于,文本字段是一个混合类型(字符串和整数)的数组。因此,所有条目都被转换为字符串,我无法确定数组中哪些条目是字符串,哪些是整数。我不能使用parseInt,因为原始数组中的条目可能既有“2”又有3。
有没有办法在转换为Java对象后获取数组字段的正确实例类型呢?
解决方案:
所以我用了Gson的JsonDeserializer实现了一个绕路的解决方法。然后我尝试使用Jackson,你猜怎么着,Jackson支持通过保留数据类型来序列化/反序列化混合数组类型。
ObjectMapper mapper = new ObjectMapper();
MyPojo gmEntry = mapper.readValue(json, new TypeReference<MyPojo >(){});

我基本上可以获取List<Object>并使用instanceof检查数据类型。

真可惜,Gson!


棘手的情况。也许你已经尝试过了,但是是否有可能分别维护数据,即字符串和数字? - undefined
没错,我无法单独维护它。 - undefined
数据中既包含整数字符串,也包含整数这一事实对于gson来说是未知的。基于List<String>,它将所有内容转换为字符串。一旦完成这个过程,似乎没有办法单独获取整数,而不获取实际上是整数的字符串。对我来说,看起来是个死胡同。 - undefined
我并不局限于使用gson。还有其他的库可以帮助吗? - undefined
5个回答

1
通过自定义类和添加类型适配器,您可以操纵字符串(json.toString()返回带有“”引号的字符串,因此您可以看到它是否为字符串)。
输出:(类似乎是正确的)
class test.Main$StringPojo pojo{object=foo}
class test.Main$IntPojo pojo{object=1}
class test.Main$StringPojo pojo{object=bar}
class test.Main$StringPojo pojo{object=2}
class test.Main$IntPojo pojo{object=3}
public static void main(final String[] args){


    String str = "{\n" +
            "  \"text\": [\"foo\",1,\"bar\",\"2\",3],\n" +
            "  \"text1\": \"value1\" }";

    GsonBuilder builder = new GsonBuilder();
    builder.registerTypeAdapter(pojo.class, new JsonDeserializer<pojo>() {
        @Override
        public pojo deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
            try {
                return new IntPojo(Integer.parseInt(json.toString()));
            } catch (Exception e) {
                return new StringPojo(json.getAsString());
            }
        }
    });
    MyPojo myPojo = builder.create().fromJson(str, MyPojo.class);
    for (pojo pojo : myPojo.text) {
        System.out.println(pojo.getClass() + " " + pojo.object);
    }
}

public static abstract class  pojo{
    protected Object object;

    public pojo() {
    }

    @Override
    public String toString() {
        return "pojo{" +
                "object=" + object +
                '}';
    }
}

public static class StringPojo extends pojo{
    public StringPojo(String str) {
        object = str;
    }
}

public static class IntPojo extends pojo{

    public IntPojo(int intt) {
        this.object = intt;
    }
}
public static class MyPojo {
    List<pojo> text;
    String text1;
}

请问您能否将代码库更新为Java 7的等效版本? - undefined
没关系,我已经能够在Java7中解决这个问题了。看起来很有希望。让我试一下,然后告诉你结果。 - undefined
由于您自己创建对象,您可以根据需要进行初始化(无需使用抽象类),我已将其编辑为Java 7版本。 - undefined
这就是我提出的一样! - undefined
你提出了一个数据结构,而不是一种使用gson解析数组中混合类型的方法。当使用该库运行你的代码时,会抛出异常。 - undefined
所以我花了一些时间,让它正常工作了。然后我尝试使用Jackson来做同样的事情,你猜怎么着?Jackson支持序列化/反序列化混合数组类型并保留数据类型。Gson真是丢人! - undefined

0

我看了一下。那里给出的例子是将数组作为顶级元素。而在我的情况下,不是这样。因此,我需要自己解析JSON字符串,然后确定它是JsonArray还是JsonObject,并且无法利用直接将JSON转换为Java对象的好处。另外,在给出的例子中,数组元素的顺序似乎是预定义的,而在我的情况下并非如此。 - undefined

0

正如你所写的 - 你定义了:List<String> text; 但是该列表也包含整数。

Java 是强类型语言,请考虑将 List 声明为 List<Object>(不太推荐)或创建一个只包含单一类型变量的 JSON 列表(更推荐)。


1
将其定义为List<Object>的问题在于我无法确定List的哪些元素是整数,哪些是字符串。getClass()方法返回的是java.lang.Object。 - undefined
当然,因为这是List的类型 :) 这也是我写下它不是首选方式的原因 - 你可以这样做,但你必须做一些丑陋的事情来使其工作。例如:Object[] a = {"a", 1}; System.out.println(Integer.valueOf((String.valueOf(a[1])))); 然后用try/catch包围起来,以防它不是一个int等等。 - undefined
就像我在帖子中提到的那样,我不能使用Integer.valueOf,因为我的JSON数组既可以是"3",也可以是2,例如["3", 2]。 - undefined
你可以将JSON作为字符串获取并自行解析,检查每个项目是否被引号包围。但是,你必须自己实现它,而不能使用现有的JSON库。正如我之前提到的,这是一种糟糕的做法,代码会显得丑陋(而且维护起来也不好玩...)。一个更好的方法是重新考虑架构,并传递包含相同类型的JSON数组。请记住,Java是强类型语言,不像Javascript/Python/Ruby等。 - undefined
嗯,猜猜看,杰克逊支持这个非常容易。 - undefined

0
你可以创建一个抽象类 ItemType(用作数组项类型),并从中继承两个包装类:一个用于 int 类型,另一个用于 string 类型。
abstract class ItemType {
    protected Object value;
}
class IntType extends ItemType {
    IntType(Integer value){
        this.value = value;
    }
}
class StringType extends ItemType {
    IntType(String value){
        this.value = value;
    }
}

尝试一下这个代码:List<ItemType> text;

我尝试了这个,但是它抛出了一个异常:"com.google.gson.JsonParseException: 期望找到对象,而实际上找到的是 foo"。 - undefined
StringTypešÜäŠ×äÚÇáň篊Ľ░ň║öŔ»ąŠś»StringType(String value)ŃÇé - undefined

0

不确定这是否是您所需要的,但这是我用于解析JSON的代码。

static public void newsParser(String urlString, String targetObject) throws FileNotFoundException, IOException
    {

        URL url = new URL(urlString);

        JSONParser parser=new JSONParser();


           BufferedReader br = new BufferedReader(new InputStreamReader(url.openStream()));



           Object obj;
        try 
        {
            obj = parser.parse(br);         
            //JSONObject jsonObject = (JSONObject) obj;
            JSONArray jsonArray = (JSONArray) obj;

            Iterator<?> i = jsonArray.iterator();

            while (i.hasNext())
            {
                slide = (JSONObject) i.next();
                newsInfo = (String)slide.get(targetObject);   
                System.out.println(newsInfo);
                newsTitles.add(newsInfo);


            }
        } 
        catch (ParseException e) 
        {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

    }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接